profit-planet-frontend/src/app/admin/language-management/components/LanguageManagementTopSection.tsx
DeathKaioken e19164a471 Cringe
Co-authored-by: Copilot <copilot@github.com>
2026-05-03 23:46:38 +02:00

201 lines
7.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import type { RefObject } from 'react';
import { useMemo } from 'react';
import { useTranslation } from '../../../i18n/useTranslation';
type LanguageEntry = {
code: string;
name: string;
};
type Props = {
headerRef: RefObject<HTMLDivElement | null>;
totalKeys: number;
onScan: () => void;
isScanning: boolean;
isAutoFixing: boolean;
onBackToAdmin: () => void;
isDirty: boolean;
onSave: () => void;
saved: boolean;
saveError: string;
allLanguages: LanguageEntry[];
activeLang: string;
setActiveLang: (code: string) => void;
isBuiltin: (code: string) => boolean;
onDeleteLanguageRequest: (code: string) => void;
onOpenAddLanguage: () => void;
allTabStats: { total: number; translated: number; missing: number };
translationProgressPercent: number;
wizardMissingKeysCount: number;
onOpenTranslationWizard: () => void;
};
export default function LanguageManagementTopSection({
headerRef,
totalKeys,
onScan,
isScanning,
isAutoFixing,
onBackToAdmin,
isDirty,
onSave,
saved,
saveError,
allLanguages,
activeLang,
setActiveLang,
isBuiltin,
onDeleteLanguageRequest,
onOpenAddLanguage,
allTabStats,
translationProgressPercent,
wizardMissingKeysCount,
onOpenTranslationWizard,
}: Props) {
const { t } = useTranslation();
const prioritizedLanguages = useMemo(() => {
const byCode = new Map(allLanguages.map((lang) => [lang.code, lang]));
const english = byCode.get('en');
const german = byCode.get('de');
const rest = allLanguages
.filter((lang) => lang.code !== 'en' && lang.code !== 'de')
.sort((a, b) => a.name.localeCompare(b.name));
return [english, german, ...rest].filter((lang): lang is LanguageEntry => Boolean(lang));
}, [allLanguages]);
const englishLanguage = prioritizedLanguages.find((lang) => lang.code === 'en');
const germanLanguage = prioritizedLanguages.find((lang) => lang.code === 'de');
const otherLanguages = prioritizedLanguages.filter((lang) => lang.code !== 'en' && lang.code !== 'de');
const renderLanguageButton = (lang: LanguageEntry) => (
<button
key={lang.code}
onClick={() => setActiveLang(lang.code)}
className={`relative rounded-lg px-4 py-2 text-sm font-medium transition flex items-center gap-2 ${
activeLang === lang.code
? 'bg-[#1C2B4A] text-white shadow'
: 'border border-gray-300 bg-white text-gray-700 hover:bg-gray-50'
}`}
>
{lang.name}
<span className="text-xs opacity-60">({lang.code})</span>
{!isBuiltin(lang.code) && (
<button
onClick={(e) => {
e.stopPropagation();
onDeleteLanguageRequest(lang.code);
}}
title={t('autofix.k5fcc9b0e')}
className={`ml-1 inline-flex items-center justify-center rounded-full w-4 h-4 text-xs leading-none ${
activeLang === lang.code
? 'bg-white/20 hover:bg-white/40 text-white'
: 'bg-gray-200 hover:bg-red-100 text-gray-500 hover:text-red-600'
}`}
>
×
</button>
)}
</button>
);
return (
<>
<div ref={headerRef} className="flex items-center justify-between flex-wrap gap-4">
<div>
<h1 className="text-3xl font-bold text-[#1C2B4A]">{t('autofix.k346a2c64')}</h1>
<p className="text-sm text-gray-500 mt-1">
Manage UI translations. All {totalKeys} keys scanned from the English source file.
</p>
</div>
<div className="flex items-center gap-3 flex-wrap">
<button
onClick={onScan}
disabled={isScanning || isAutoFixing}
className="rounded-md border border-[#1C2B4A] text-[#1C2B4A] px-3 py-2 text-sm font-medium hover:bg-[#1C2B4A] hover:text-white transition-colors flex items-center gap-2 disabled:opacity-50"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4" />
</svg>
{isScanning ? 'Scanning...' : 'Scan & review fixes'}
</button>
<button
onClick={onBackToAdmin}
className="rounded-md border border-gray-300 px-3 py-2 text-sm hover:bg-gray-50"
>{t('autofix.kea7cde7a')}</button>
{isDirty && (
<button
onClick={onSave}
className="rounded-md bg-[#1C2B4A] text-white px-4 py-2 text-sm font-semibold hover:bg-[#1C2B4A]/90"
>{t('autofix.k4be6f631')}</button>
)}
{saved && !isDirty && (
<span className="rounded-md bg-green-50 border border-green-200 text-green-700 px-3 py-2 text-sm font-medium">
Saved
</span>
)}
</div>
</div>
{saveError && (
<div className="rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700">
{saveError}
</div>
)}
<div className="flex items-center gap-2 flex-wrap">
{englishLanguage && renderLanguageButton(englishLanguage)}
{germanLanguage && renderLanguageButton(germanLanguage)}
<button
onClick={onOpenAddLanguage}
className="rounded-lg border-2 border-dashed border-gray-300 px-4 py-2 text-sm text-gray-500 hover:border-[#1C2B4A] hover:text-[#1C2B4A] transition"
>
+ Add language
</button>
{otherLanguages.map((lang) => renderLanguageButton(lang))}
</div>
{activeLang !== 'en' && (
<div className="rounded-xl border border-gray-200 bg-white p-4 flex items-center gap-4">
<div className="flex-1">
<div className="flex justify-between text-xs text-gray-500 mb-1">
<span>{t('autofix.kb8f33873')}</span>
<span>{allTabStats.translated} / {allTabStats.total} keys translated</span>
</div>
<div className="h-2 rounded-full bg-gray-100 overflow-hidden">
<div
className="h-full rounded-full bg-[#1C2B4A] transition-all"
style={{ width: `${translationProgressPercent}%` }}
/>
</div>
</div>
<span className="text-lg font-bold text-[#1C2B4A]">
{translationProgressPercent}%
</span>
</div>
)}
{activeLang !== 'en' && allTabStats.missing > 0 && wizardMissingKeysCount > 0 && (
<div className="rounded-xl border border-indigo-200 bg-indigo-50 p-4 flex items-start justify-between gap-4">
<div>
<p className="text-sm font-semibold text-indigo-900">{t('autofix.k5e5e8744')}</p>
<p className="text-xs text-indigo-800 mt-1">
{allLanguages.find((l) => l.code === activeLang)?.name ?? activeLang} still has {wizardMissingKeysCount} missing keys. Start the wizard to fill them step by step.
</p>
</div>
<div className="flex items-center gap-2 shrink-0">
<button
type="button"
onClick={onOpenTranslationWizard}
className="rounded-md bg-[#1C2B4A] text-white px-3 py-1.5 text-xs font-semibold hover:bg-[#1C2B4A]/90"
>{t('autofix.k725dd1d6')}</button>
</div>
</div>
)}
</>
);
}