fix: full translation parity, component consistency, and link clickability
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 24s
Build & Deploy / 🧪 QA (push) Successful in 1m47s
Build & Deploy / 🏗️ Build (push) Successful in 2m46s
Build & Deploy / 🚀 Deploy (push) Successful in 25s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 44s
Build & Deploy / 🔔 Notify (push) Successful in 1s
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 24s
Build & Deploy / 🧪 QA (push) Successful in 1m47s
Build & Deploy / 🏗️ Build (push) Successful in 2m46s
Build & Deploy / 🚀 Deploy (push) Successful in 25s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 44s
Build & Deploy / 🔔 Notify (push) Successful in 1s
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { motion, useScroll, useTransform } from 'framer-motion';
|
import { motion, useScroll, useTransform } from 'framer-motion';
|
||||||
import { Building2, Compass, Layers, ArrowDownToLine, Wrench, Factory, Zap, MapPin, CheckCircle2 } from 'lucide-react';
|
import { Building2, Compass, Layers, ArrowDownToLine, Wrench, Factory, Zap, MapPin, CheckCircle2 } from 'lucide-react';
|
||||||
|
import { useTranslations } from 'next-intl';
|
||||||
|
|
||||||
const iconMap: Record<string, React.ElementType> = {
|
const iconMap: Record<string, React.ElementType> = {
|
||||||
Building2,
|
Building2,
|
||||||
@@ -16,37 +17,6 @@ const iconMap: Record<string, React.ElementType> = {
|
|||||||
CheckCircle2
|
CheckCircle2
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultMilestones = [
|
|
||||||
{
|
|
||||||
date: '16.12.2015',
|
|
||||||
year: '2015',
|
|
||||||
title: 'Gründung E-TIB GmbH',
|
|
||||||
desc: 'Ausführung elektrischer Infrastrukturprojekte, Kabeltiefbau und Horizontalspülbohrungen.',
|
|
||||||
iconName: 'Building2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
date: '04.02.2019',
|
|
||||||
year: '2019',
|
|
||||||
title: 'Gründung E-TIB Ingenieurgesellschaft',
|
|
||||||
desc: 'Genehmigungs- und Ausführungsplanung, komplexe Querungen sowie Netzanschlussplanung.',
|
|
||||||
iconName: 'Compass',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
date: '14.11.2019',
|
|
||||||
year: '2019',
|
|
||||||
title: 'Gründung E-TIB Verwaltung GmbH',
|
|
||||||
desc: 'Zentrale Dienste, Erwerb, Vermietung, Verpachtung und Verwaltung von Immobilien und Maschinen.',
|
|
||||||
iconName: 'Layers',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
date: '21.10.2025',
|
|
||||||
year: '2025',
|
|
||||||
title: 'Gründung E-TIB Bohrtechnik GmbH',
|
|
||||||
desc: 'Spezialisierung auf präzise Horizontalspülbohrungen in allen Bodenklassen.',
|
|
||||||
iconName: 'ArrowDownToLine',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
interface Milestone {
|
interface Milestone {
|
||||||
date: string;
|
date: string;
|
||||||
year: string;
|
year: string;
|
||||||
@@ -62,10 +32,45 @@ interface CompanyTimelineProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function CompanyTimeline({
|
export function CompanyTimeline({
|
||||||
badge = 'Unsere Geschichte',
|
badge,
|
||||||
title = 'Meilensteine der Entwicklung',
|
title,
|
||||||
milestones = defaultMilestones
|
milestones
|
||||||
}: CompanyTimelineProps) {
|
}: CompanyTimelineProps) {
|
||||||
|
const t = useTranslations('CompanyTimeline');
|
||||||
|
|
||||||
|
const finalBadge = badge || t('badge');
|
||||||
|
const finalTitle = title || t('title');
|
||||||
|
|
||||||
|
const finalMilestones = milestones || [
|
||||||
|
{
|
||||||
|
date: '16.12.2015',
|
||||||
|
year: '2015',
|
||||||
|
title: t('milestones.2015.title'),
|
||||||
|
desc: t('milestones.2015.desc'),
|
||||||
|
iconName: 'Building2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: '04.02.2019',
|
||||||
|
year: '2019',
|
||||||
|
title: t('milestones.2019_ing.title'),
|
||||||
|
desc: t('milestones.2019_ing.desc'),
|
||||||
|
iconName: 'Compass',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: '14.11.2019',
|
||||||
|
year: '2019',
|
||||||
|
title: t('milestones.2019_verw.title'),
|
||||||
|
desc: t('milestones.2019_verw.desc'),
|
||||||
|
iconName: 'Layers',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: '21.10.2025',
|
||||||
|
year: '2025',
|
||||||
|
title: t('milestones.2025.title'),
|
||||||
|
desc: t('milestones.2025.desc'),
|
||||||
|
iconName: 'ArrowDownToLine',
|
||||||
|
},
|
||||||
|
];
|
||||||
const containerRef = React.useRef<HTMLDivElement>(null);
|
const containerRef = React.useRef<HTMLDivElement>(null);
|
||||||
const { scrollYProgress } = useScroll({
|
const { scrollYProgress } = useScroll({
|
||||||
target: containerRef,
|
target: containerRef,
|
||||||
@@ -84,10 +89,10 @@ export function CompanyTimeline({
|
|||||||
<div className="text-center mb-24">
|
<div className="text-center mb-24">
|
||||||
<div className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-white border border-neutral-200 text-neutral-dark text-xs font-bold uppercase tracking-wider mb-6 shadow-sm">
|
<div className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-white border border-neutral-200 text-neutral-dark text-xs font-bold uppercase tracking-wider mb-6 shadow-sm">
|
||||||
<span className="w-2 h-2 rounded-full bg-primary animate-pulse" />
|
<span className="w-2 h-2 rounded-full bg-primary animate-pulse" />
|
||||||
{badge}
|
{finalBadge}
|
||||||
</div>
|
</div>
|
||||||
<h3 className="font-heading text-4xl md:text-5xl lg:text-6xl font-extrabold text-neutral-dark tracking-tight">
|
<h3 className="font-heading text-4xl md:text-5xl lg:text-6xl font-extrabold text-neutral-dark tracking-tight">
|
||||||
{title}
|
{finalTitle}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -104,7 +109,7 @@ export function CompanyTimeline({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-16 md:space-y-24">
|
<div className="space-y-16 md:space-y-24">
|
||||||
{milestones.map((milestone, i) => {
|
{finalMilestones.map((milestone, i) => {
|
||||||
const isEven = i % 2 === 0;
|
const isEven = i % 2 === 0;
|
||||||
const Icon = iconMap[milestone.iconName] || Building2;
|
const Icon = iconMap[milestone.iconName] || Building2;
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import Image from 'next/image';
|
|||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { AnimatedGlossyBorder } from '@/components/ui/AnimatedGlossyBorder';
|
import { AnimatedGlossyBorder } from '@/components/ui/AnimatedGlossyBorder';
|
||||||
import { Location, defaultLocations, minorLocations } from '@/lib/map-data';
|
import { Location, defaultLocations, minorLocations } from '@/lib/map-data';
|
||||||
import { useLocale } from 'next-intl';
|
import { useLocale, useTranslations } from 'next-intl';
|
||||||
|
|
||||||
const allLocations = [...defaultLocations, ...minorLocations];
|
const allLocations = [...defaultLocations, ...minorLocations];
|
||||||
|
|
||||||
@@ -27,9 +27,9 @@ interface InteractiveGermanyMapProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function InteractiveGermanyMap({
|
export function InteractiveGermanyMap({
|
||||||
badge = 'Einsatzgebiete',
|
badge,
|
||||||
title = <>Deutschlandweit<br/>für Sie im Einsatz.</>,
|
title,
|
||||||
description = 'Von unseren strategischen Standorten in Guben und Bülstedt steuern und realisieren wir komplexe Infrastrukturprojekte im gesamten Bundesgebiet.',
|
description,
|
||||||
stats = [
|
stats = [
|
||||||
{ value: '100', suffix: '%', label: 'Überregionale Reichweite' },
|
{ value: '100', suffix: '%', label: 'Überregionale Reichweite' },
|
||||||
{ value: '2', suffix: '+', label: 'Operative Standorte' },
|
{ value: '2', suffix: '+', label: 'Operative Standorte' },
|
||||||
@@ -40,6 +40,13 @@ export function InteractiveGermanyMap({
|
|||||||
const [activeLocation, setActiveLocation] = useState<Location | null>(null);
|
const [activeLocation, setActiveLocation] = useState<Location | null>(null);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const locale = useLocale();
|
const locale = useLocale();
|
||||||
|
const t = useTranslations('InteractiveGermanyMap');
|
||||||
|
const tStandard = useTranslations('StandardPage');
|
||||||
|
|
||||||
|
const finalBadge = badge || tStandard('badge');
|
||||||
|
// the map is mostly used with specific props, so we leave title & description to fallbacks if not provided
|
||||||
|
const finalTitle = title || (locale === 'en' ? <>Nationwide<br/>in operation for you.</> : <>Deutschlandweit<br/>für Sie im Einsatz.</>);
|
||||||
|
const finalDescription = description || (locale === 'en' ? 'From our strategic locations in Guben and Bülstedt, we control and implement complex infrastructure projects nationwide.' : 'Von unseren strategischen Standorten in Guben und Bülstedt steuern und realisieren wir komplexe Infrastrukturprojekte im gesamten Bundesgebiet.');
|
||||||
|
|
||||||
const hq = locations.find((l) => l.type === 'hq');
|
const hq = locations.find((l) => l.type === 'hq');
|
||||||
const branch = locations.find((l) => l.type === 'branch');
|
const branch = locations.find((l) => l.type === 'branch');
|
||||||
@@ -62,21 +69,21 @@ export function InteractiveGermanyMap({
|
|||||||
<div className="xl:col-span-5 text-white z-20">
|
<div className="xl:col-span-5 text-white z-20">
|
||||||
<div className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-primary/10 border border-primary/20 text-primary text-xs font-bold uppercase tracking-wider mb-8">
|
<div className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-primary/10 border border-primary/20 text-primary text-xs font-bold uppercase tracking-wider mb-8">
|
||||||
<MapPin className="w-4 h-4" />
|
<MapPin className="w-4 h-4" />
|
||||||
<span>{badge}</span>
|
<span>{finalBadge}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isHero ? (
|
{isHero ? (
|
||||||
<h1 className="font-heading text-4xl lg:text-5xl xl:text-6xl font-extrabold mb-6 leading-[1.1] text-transparent bg-clip-text bg-gradient-to-r from-white to-white/70 break-words [hyphens:auto]">
|
<h1 className="font-heading text-4xl lg:text-5xl xl:text-6xl font-extrabold mb-6 leading-[1.1] text-transparent bg-clip-text bg-gradient-to-r from-white to-white/70 break-words [hyphens:auto]">
|
||||||
{title}
|
{finalTitle}
|
||||||
</h1>
|
</h1>
|
||||||
) : (
|
) : (
|
||||||
<h3 className="font-heading text-4xl lg:text-5xl xl:text-6xl font-extrabold mb-6 leading-[1.1] text-transparent bg-clip-text bg-gradient-to-r from-white to-white/70 break-words [hyphens:auto]">
|
<h3 className="font-heading text-4xl lg:text-5xl xl:text-6xl font-extrabold mb-6 leading-[1.1] text-transparent bg-clip-text bg-gradient-to-r from-white to-white/70 break-words [hyphens:auto]">
|
||||||
{title}
|
{finalTitle}
|
||||||
</h3>
|
</h3>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<p className="text-white/60 text-lg mb-12 leading-relaxed">
|
<p className="text-white/60 text-lg mb-12 leading-relaxed">
|
||||||
{description}
|
{finalDescription}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* Industrial Stats Grid */}
|
{/* Industrial Stats Grid */}
|
||||||
@@ -204,9 +211,7 @@ export function InteractiveGermanyMap({
|
|||||||
<div className="flex items-center gap-2 mb-1">
|
<div className="flex items-center gap-2 mb-1">
|
||||||
<MapPin className="w-3.5 h-3.5 text-primary" />
|
<MapPin className="w-3.5 h-3.5 text-primary" />
|
||||||
<span className="text-xs font-bold text-primary uppercase tracking-wider">
|
<span className="text-xs font-bold text-primary uppercase tracking-wider">
|
||||||
{activeLocation.type === 'hq' ? 'Hauptsitz' :
|
{t(`types.${activeLocation.type === 'minor_node' ? 'project' : activeLocation.type}`)}
|
||||||
activeLocation.type === 'branch' ? 'Niederlassung' :
|
|
||||||
activeLocation.type === 'minor_node' ? 'Projekt' : 'Referenz'}
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="font-heading font-bold text-lg leading-tight mb-2">
|
<div className="font-heading font-bold text-lg leading-tight mb-2">
|
||||||
@@ -218,12 +223,7 @@ export function InteractiveGermanyMap({
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="text-white/60 text-xs mb-3">
|
<div className="text-white/60 text-xs mb-3">
|
||||||
{activeLocation.description === 'wind' ? 'Errichtung Leitungstrassen & Netzanbindung für Windpark-Infrastruktur.' :
|
{t(`descriptions.${['wind','pv','fiber','power','battery'].includes(activeLocation.description || '') ? activeLocation.description : 'default'}`)}
|
||||||
activeLocation.description === 'pv' ? 'Bau von Mittelspannungstrassen zur Einspeisung der PV-Anlage.' :
|
|
||||||
activeLocation.description === 'fiber' ? 'Komplexer FTTx Breitbandausbau inkl. LWL-Montage & Tiefbau.' :
|
|
||||||
activeLocation.description === 'power' ? '110kV Hochspannungstrasse Erdkabelverlegung.' :
|
|
||||||
activeLocation.description === 'battery' ? 'Infrastrukturausbau für BESS (Batteriespeicher).' :
|
|
||||||
'Komplexes Infrastrukturprojekt (Tiefbau & HDD).'}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -233,17 +233,11 @@ export function InteractiveGermanyMap({
|
|||||||
<>
|
<>
|
||||||
<li className="text-[11px] text-white/80 flex items-start gap-2 font-medium">
|
<li className="text-[11px] text-white/80 flex items-start gap-2 font-medium">
|
||||||
<CheckCircle2 className="w-3 h-3 text-primary shrink-0 mt-0.5" />
|
<CheckCircle2 className="w-3 h-3 text-primary shrink-0 mt-0.5" />
|
||||||
<span>{
|
<span>{t(`features.${['wind','pv','fiber','power','battery'].includes(activeLocation.description || '') ? activeLocation.description : 'default'}`)}</span>
|
||||||
activeLocation.description === 'wind' ? 'Netzanbindung Windpark' :
|
|
||||||
activeLocation.description === 'pv' ? 'Einspeisung PV-Anlage' :
|
|
||||||
activeLocation.description === 'fiber' ? 'FTTx Infrastruktur' :
|
|
||||||
activeLocation.description === 'power' ? '110kV Trasse' :
|
|
||||||
activeLocation.description === 'battery' ? 'BESS Anschluss' : 'Infrastrukturprojekt'
|
|
||||||
}</span>
|
|
||||||
</li>
|
</li>
|
||||||
<li className="text-[11px] text-white/80 flex items-start gap-2 font-medium">
|
<li className="text-[11px] text-white/80 flex items-start gap-2 font-medium">
|
||||||
<CheckCircle2 className="w-3 h-3 text-primary shrink-0 mt-0.5" />
|
<CheckCircle2 className="w-3 h-3 text-primary shrink-0 mt-0.5" />
|
||||||
<span>Tiefbau & Spülbohrung (HDD)</span>
|
<span>{t('features.method')}</span>
|
||||||
</li>
|
</li>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
@@ -259,7 +253,7 @@ export function InteractiveGermanyMap({
|
|||||||
|
|
||||||
{activeLocation.href && (
|
{activeLocation.href && (
|
||||||
<div className="inline-flex items-center text-xs font-bold text-primary">
|
<div className="inline-flex items-center text-xs font-bold text-primary">
|
||||||
{locale === 'en' ? 'Learn more' : 'Zum Projekt'}
|
{t('learnMore')}
|
||||||
<ArrowUpRight className="w-3.5 h-3.5 ml-1" />
|
<ArrowUpRight className="w-3.5 h-3.5 ml-1" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|||||||
import { describe, it, expect, vi } from 'vitest';
|
import { describe, it, expect, vi } from 'vitest';
|
||||||
import { render, screen, fireEvent } from '@testing-library/react';
|
import { render, screen, fireEvent } from '@testing-library/react';
|
||||||
import { ReferencesSlider, Reference } from './ReferencesSlider';
|
import { ReferencesSlider, Reference } from './ReferencesSlider';
|
||||||
|
import { NextIntlClientProvider } from 'next-intl';
|
||||||
|
|
||||||
// Mock next/link to render standard <a> tag
|
// Mock next/link to render standard <a> tag
|
||||||
vi.mock('next/link', () => ({
|
vi.mock('next/link', () => ({
|
||||||
@@ -21,6 +22,13 @@ vi.mock('next/image', () => ({
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Mock next-intl
|
||||||
|
vi.mock('next-intl', () => ({
|
||||||
|
useTranslations: () => (key: string) => key,
|
||||||
|
useLocale: () => 'en',
|
||||||
|
NextIntlClientProvider: ({ children }: any) => <>{children}</>
|
||||||
|
}));
|
||||||
|
|
||||||
describe('ReferencesSlider TDD', () => {
|
describe('ReferencesSlider TDD', () => {
|
||||||
const mockReferences: Reference[] = [
|
const mockReferences: Reference[] = [
|
||||||
{
|
{
|
||||||
@@ -49,8 +57,8 @@ describe('ReferencesSlider TDD', () => {
|
|||||||
|
|
||||||
const links = screen.getAllByTestId('reference-tile-link');
|
const links = screen.getAllByTestId('reference-tile-link');
|
||||||
expect(links).toHaveLength(2);
|
expect(links).toHaveLength(2);
|
||||||
expect(links[0].getAttribute('href')).toBe('/referenzen/referenz-projekt-eins');
|
expect(links[0].getAttribute('href')).toBe('/en/referenzen/referenz-projekt-eins');
|
||||||
expect(links[1].getAttribute('href')).toBe('/referenzen/referenz-projekt-zwei');
|
expect(links[1].getAttribute('href')).toBe('/en/referenzen/referenz-projekt-zwei');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows navigation on simple click (no drag)', () => {
|
it('allows navigation on simple click (no drag)', () => {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { motion } from 'framer-motion';
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { HoverShineOverlay } from '@/components/ui/HoverShineOverlay';
|
import { HoverShineOverlay } from '@/components/ui/HoverShineOverlay';
|
||||||
|
import { useTranslations, useLocale } from 'next-intl';
|
||||||
|
|
||||||
export interface Reference {
|
export interface Reference {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -34,6 +35,9 @@ interface ReferencesSliderProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function ReferencesSlider(props: ReferencesSliderProps) {
|
export function ReferencesSlider(props: ReferencesSliderProps) {
|
||||||
|
const t = useTranslations('ReferencesSlider');
|
||||||
|
const locale = useLocale();
|
||||||
|
|
||||||
const { data } = props;
|
const { data } = props;
|
||||||
const references = props.references || [];
|
const references = props.references || [];
|
||||||
const containerRef = React.useRef<HTMLDivElement>(null);
|
const containerRef = React.useRef<HTMLDivElement>(null);
|
||||||
@@ -43,11 +47,11 @@ export function ReferencesSlider(props: ReferencesSliderProps) {
|
|||||||
const isDraggingRef = React.useRef(false);
|
const isDraggingRef = React.useRef(false);
|
||||||
const [isDragging, setIsDragging] = React.useState(false);
|
const [isDragging, setIsDragging] = React.useState(false);
|
||||||
|
|
||||||
const badge = props.badge || data?.badge || 'Ausgewählte Projekte';
|
const badge = props.badge || data?.badge || t('badge');
|
||||||
const title = props.title || data?.title || 'Referenzen & Erfolge';
|
const title = props.title || data?.title || t('title');
|
||||||
const description = props.description || data?.description || 'Ein Auszug unserer erfolgreich abgeschlossenen Projekte im Bereich Kabeltiefbau, Bohrtechnik und Netzinfrastruktur.';
|
const description = props.description || data?.description || t('description');
|
||||||
const ctaLabel = props.ctaLabel || data?.ctaLabel || 'Alle Referenzen ansehen';
|
const ctaLabel = props.ctaLabel || data?.ctaLabel || t('ctaLabel');
|
||||||
const ctaHref = props.ctaHref || data?.ctaHref || '/referenzen';
|
const ctaHref = props.ctaHref || data?.ctaHref || `/${locale}/referenzen`;
|
||||||
|
|
||||||
if (!references || references.length === 0) return null;
|
if (!references || references.length === 0) return null;
|
||||||
|
|
||||||
@@ -132,7 +136,7 @@ export function ReferencesSlider(props: ReferencesSliderProps) {
|
|||||||
className="flex-shrink-0 w-[320px] md:w-[480px] snap-center group pointer-events-auto"
|
className="flex-shrink-0 w-[320px] md:w-[480px] snap-center group pointer-events-auto"
|
||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
href={`/referenzen/${ref.slug}`}
|
href={`/${locale}/referenzen/${ref.slug}`}
|
||||||
onClick={handleTileClick}
|
onClick={handleTileClick}
|
||||||
data-testid="reference-tile-link"
|
data-testid="reference-tile-link"
|
||||||
className="block relative aspect-[16/10] bg-neutral-800 rounded-2xl overflow-hidden mb-5 border border-white/5 shadow-2xl"
|
className="block relative aspect-[16/10] bg-neutral-800 rounded-2xl overflow-hidden mb-5 border border-white/5 shadow-2xl"
|
||||||
|
|||||||
@@ -28,20 +28,20 @@ describe('LanguageSwitcher TDD', () => {
|
|||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('translates /en/events to /de/messen when switching to German', () => {
|
it('translates /en/trade-fairs to /de/messen when switching to German', () => {
|
||||||
vi.mocked(usePathname).mockReturnValue('/en/events');
|
(usePathname as any).mockReturnValue('/en/trade-fairs');
|
||||||
render(<LanguageSwitcher />);
|
render(<LanguageSwitcher />);
|
||||||
|
|
||||||
const deLink = screen.getByLabelText('Switch to Deutsch');
|
const deLink = screen.getByLabelText('Switch to Deutsch');
|
||||||
expect(deLink.getAttribute('href')).toBe('/de/messen');
|
expect(deLink.getAttribute('href')).toBe('/de/messen');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('translates /de/messen to /en/events when switching to English', () => {
|
it('translates /de/messen to /en/trade-fairs when switching to English', () => {
|
||||||
vi.mocked(usePathname).mockReturnValue('/de/messen');
|
(usePathname as any).mockReturnValue('/de/messen');
|
||||||
render(<LanguageSwitcher />);
|
render(<LanguageSwitcher />);
|
||||||
|
|
||||||
const enLink = screen.getByLabelText('Switch to English');
|
const enLink = screen.getByLabelText('Switch to English');
|
||||||
expect(enLink.getAttribute('href')).toBe('/en/events');
|
expect(enLink.getAttribute('href')).toBe('/en/trade-fairs');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('translates /en/about-us to /de/ueber-uns when switching to German', () => {
|
it('translates /en/about-us to /de/ueber-uns when switching to German', () => {
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ layout: "fullBleed"
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<InteractiveGermanyMap isHero={false} badge="Bundesweite Präsenz" title="Infrastruktur für ein ganzes Land" description="Seit 2023 haben wir in über 100 Projekten quer durch Deutschland bewiesen, dass wir Infrastrukturprojekte jeder Größenordnung verlässlich umsetzen." />
|
<InteractiveGermanyMap isHero={true} badge="Bundesweite Präsenz" title="Infrastruktur für ein ganzes Land" description="Seit 2023 haben wir in über 100 Projekten quer durch Deutschland bewiesen, dass wir Infrastrukturprojekte jeder Größenordnung verlässlich umsetzen." />
|
||||||
|
|
||||||
<CompanyTimeline />
|
<CompanyTimeline />
|
||||||
|
|
||||||
|
|||||||
@@ -52,42 +52,9 @@ layout: "fullBleed"
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<InteractiveGermanyMap isHero={false} badge="Nationwide Presence" title="Infrastructure for an entire country" description="Since 2023, we have proven in over 100 projects across Germany that we reliably implement infrastructure projects of any scale." />
|
<InteractiveGermanyMap isHero={true} badge="Nationwide Presence" title="Infrastructure for an entire country" description="Since 2023, we have proven in over 100 projects across Germany that we reliably implement infrastructure projects of any scale." />
|
||||||
|
|
||||||
<CompanyTimeline
|
<CompanyTimeline />
|
||||||
badge="Our History"
|
|
||||||
title="Milestones of Development"
|
|
||||||
milestones={[
|
|
||||||
{
|
|
||||||
date: '16.12.2015',
|
|
||||||
year: '2015',
|
|
||||||
title: 'Foundation of E-TIB GmbH',
|
|
||||||
desc: 'Execution of electrical infrastructure projects, cable civil engineering, and horizontal directional drilling.',
|
|
||||||
iconName: 'Building2'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
date: '04.02.2019',
|
|
||||||
year: '2019',
|
|
||||||
title: 'Foundation of E-TIB Ingenieurgesellschaft',
|
|
||||||
desc: 'Approval and execution planning, complex crossings, and grid connection planning.',
|
|
||||||
iconName: 'Compass'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
date: '14.11.2019',
|
|
||||||
year: '2019',
|
|
||||||
title: 'Foundation of E-TIB Verwaltung GmbH',
|
|
||||||
desc: 'Central services, acquisition, leasing, and management of real estate and machinery.',
|
|
||||||
iconName: 'Layers'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
date: '21.10.2025',
|
|
||||||
year: '2025',
|
|
||||||
title: 'Foundation of E-TIB Bohrtechnik GmbH',
|
|
||||||
desc: 'Specialization in precise horizontal directional drilling in all soil classes.',
|
|
||||||
iconName: 'ArrowDownToLine'
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div id="structure">
|
<div id="structure">
|
||||||
<HomeSubCompanyTiles
|
<HomeSubCompanyTiles
|
||||||
|
|||||||
@@ -188,5 +188,59 @@
|
|||||||
"technical": "Technik",
|
"technical": "Technik",
|
||||||
"sustainability": "Nachhaltigkeit"
|
"sustainability": "Nachhaltigkeit"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ReferencesSlider": {
|
||||||
|
"badge": "Ausgewählte Projekte",
|
||||||
|
"title": "Referenzen & Erfolge",
|
||||||
|
"description": "Ein Auszug unserer erfolgreich abgeschlossenen Projekte im Bereich Kabeltiefbau, Bohrtechnik und Netzinfrastruktur.",
|
||||||
|
"ctaLabel": "Alle Referenzen ansehen"
|
||||||
|
},
|
||||||
|
"CompanyTimeline": {
|
||||||
|
"badge": "Unsere Geschichte",
|
||||||
|
"title": "Meilensteine der Entwicklung",
|
||||||
|
"milestones": {
|
||||||
|
"2015": {
|
||||||
|
"title": "Gründung E-TIB GmbH",
|
||||||
|
"desc": "Ausführung elektrischer Infrastrukturprojekte, Kabeltiefbau und Horizontalspülbohrungen."
|
||||||
|
},
|
||||||
|
"2019_ing": {
|
||||||
|
"title": "Gründung E-TIB Ingenieurgesellschaft",
|
||||||
|
"desc": "Genehmigungs- und Ausführungsplanung, komplexe Querungen sowie Netzanschlussplanung."
|
||||||
|
},
|
||||||
|
"2019_verw": {
|
||||||
|
"title": "Gründung E-TIB Verwaltung GmbH",
|
||||||
|
"desc": "Zentrale Dienste, Erwerb, Vermietung, Verpachtung und Verwaltung von Immobilien und Maschinen."
|
||||||
|
},
|
||||||
|
"2025": {
|
||||||
|
"title": "Gründung E-TIB Bohrtechnik GmbH",
|
||||||
|
"desc": "Spezialisierung auf präzise Horizontalspülbohrungen in allen Bodenklassen."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"InteractiveGermanyMap": {
|
||||||
|
"types": {
|
||||||
|
"hq": "Hauptsitz",
|
||||||
|
"branch": "Niederlassung",
|
||||||
|
"project": "Projekt",
|
||||||
|
"reference": "Referenz"
|
||||||
|
},
|
||||||
|
"descriptions": {
|
||||||
|
"wind": "Errichtung Leitungstrassen & Netzanbindung für Windpark-Infrastruktur.",
|
||||||
|
"pv": "Bau von Mittelspannungstrassen zur Einspeisung der PV-Anlage.",
|
||||||
|
"fiber": "Komplexer FTTx Breitbandausbau inkl. LWL-Montage & Tiefbau.",
|
||||||
|
"power": "110kV Hochspannungstrasse Erdkabelverlegung.",
|
||||||
|
"battery": "Infrastrukturausbau für BESS (Batteriespeicher).",
|
||||||
|
"default": "Komplexes Infrastrukturprojekt (Tiefbau & HDD)."
|
||||||
|
},
|
||||||
|
"features": {
|
||||||
|
"wind": "Netzanbindung Windpark",
|
||||||
|
"pv": "Einspeisung PV-Anlage",
|
||||||
|
"fiber": "FTTx Infrastruktur",
|
||||||
|
"power": "110kV Trasse",
|
||||||
|
"battery": "BESS Anschluss",
|
||||||
|
"default": "Infrastrukturprojekt",
|
||||||
|
"method": "Tiefbau & Spülbohrung (HDD)"
|
||||||
|
},
|
||||||
|
"learnMore": "Zum Projekt"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
"about-us": "ueber-uns",
|
"about-us": "ueber-uns",
|
||||||
"terms": "agb",
|
"terms": "agb",
|
||||||
"start": "start",
|
"start": "start",
|
||||||
"events": "messen"
|
"trade-fairs": "messen"
|
||||||
},
|
},
|
||||||
"products": {},
|
"products": {},
|
||||||
"categories": {}
|
"categories": {}
|
||||||
@@ -188,5 +188,59 @@
|
|||||||
"technical": "Technical",
|
"technical": "Technical",
|
||||||
"sustainability": "Sustainability"
|
"sustainability": "Sustainability"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ReferencesSlider": {
|
||||||
|
"badge": "Selected Projects",
|
||||||
|
"title": "References & Successes",
|
||||||
|
"description": "A selection of our successfully completed projects in underground cable engineering, drilling technology, and grid infrastructure.",
|
||||||
|
"ctaLabel": "View All References"
|
||||||
|
},
|
||||||
|
"CompanyTimeline": {
|
||||||
|
"badge": "Our History",
|
||||||
|
"title": "Milestones of Development",
|
||||||
|
"milestones": {
|
||||||
|
"2015": {
|
||||||
|
"title": "Foundation of E-TIB GmbH",
|
||||||
|
"desc": "Execution of electrical infrastructure projects, cable civil engineering, and horizontal directional drilling."
|
||||||
|
},
|
||||||
|
"2019_ing": {
|
||||||
|
"title": "Foundation of E-TIB Ingenieurgesellschaft",
|
||||||
|
"desc": "Permit and execution planning, complex crossings, and grid connection planning."
|
||||||
|
},
|
||||||
|
"2019_verw": {
|
||||||
|
"title": "Foundation of E-TIB Verwaltung GmbH",
|
||||||
|
"desc": "Central services, acquisition, leasing, and management of real estate and machinery."
|
||||||
|
},
|
||||||
|
"2025": {
|
||||||
|
"title": "Foundation of E-TIB Bohrtechnik GmbH",
|
||||||
|
"desc": "Specialization in precise horizontal directional drilling in all soil classes."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"InteractiveGermanyMap": {
|
||||||
|
"types": {
|
||||||
|
"hq": "Headquarters",
|
||||||
|
"branch": "Branch",
|
||||||
|
"project": "Project",
|
||||||
|
"reference": "Reference"
|
||||||
|
},
|
||||||
|
"descriptions": {
|
||||||
|
"wind": "Construction of cable routes & grid connection for wind park infrastructure.",
|
||||||
|
"pv": "Construction of medium-voltage routes for feeding PV systems.",
|
||||||
|
"fiber": "Complex FTTx broadband expansion incl. fiber optic assembly & civil engineering.",
|
||||||
|
"power": "110kV high-voltage underground cable laying.",
|
||||||
|
"battery": "Infrastructure expansion for BESS (battery storage).",
|
||||||
|
"default": "Complex infrastructure project (civil engineering & HDD)."
|
||||||
|
},
|
||||||
|
"features": {
|
||||||
|
"wind": "Grid connection wind park",
|
||||||
|
"pv": "Feeding PV system",
|
||||||
|
"fiber": "FTTx Infrastructure",
|
||||||
|
"power": "110kV Route",
|
||||||
|
"battery": "BESS Connection",
|
||||||
|
"default": "Infrastructure project",
|
||||||
|
"method": "Civil engineering & HDD"
|
||||||
|
},
|
||||||
|
"learnMore": "Learn more"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user