project-nomad/admin/inertia/components/DebugInfoModal.tsx
Martin Seener 134d1642af
Added initial i18n framework and most german translations
- Add i18next, react-i18next, i18next-browser-languagedetector packages
- Configure i18n initialization with language detector in lib/i18n.ts
- Created en/de translation files and moved most hard-coded strings into the files and translated them
- Uses locale-aware date formatting where applicable
- Added language-specific Wikipedia content files (wikipedia.en.json, wikipedia.de.json) and updated download URLs
- Added NOMAD_REPO_URL env variable for fork-friendly URL resolution (easier testing and rollout independent of Crosstalk repo)
2026-03-24 13:21:31 +01:00

105 lines
3.0 KiB
TypeScript

import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { IconBug, IconCopy, IconCheck } from '@tabler/icons-react'
import StyledModal from './StyledModal'
import api from '~/lib/api'
interface DebugInfoModalProps {
open: boolean
onClose: () => void
}
export default function DebugInfoModal({ open, onClose }: DebugInfoModalProps) {
const { t } = useTranslation()
const [debugText, setDebugText] = useState('')
const [loading, setLoading] = useState(false)
const [copied, setCopied] = useState(false)
useEffect(() => {
if (!open) return
setLoading(true)
setCopied(false)
api.getDebugInfo().then((text) => {
if (text) {
const browserLine = `Browser: ${navigator.userAgent}`
setDebugText(text + '\n' + browserLine)
} else {
setDebugText(t('debugInfo.loadFailed'))
}
setLoading(false)
}).catch(() => {
setDebugText(t('debugInfo.loadFailed'))
setLoading(false)
})
}, [open])
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(debugText)
} catch {
// Fallback for older browsers
const textarea = document.querySelector<HTMLTextAreaElement>('#debug-info-text')
if (textarea) {
textarea.select()
document.execCommand('copy')
}
}
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
return (
<StyledModal
open={open}
onClose={onClose}
title={t('debugInfo.title')}
icon={<IconBug className="size-8 text-desert-green" />}
cancelText={t('debugInfo.close')}
onCancel={onClose}
>
<p className="text-sm text-gray-500 mb-3 text-left">
{t('debugInfo.description')}
</p>
<textarea
id="debug-info-text"
readOnly
value={loading ? t('common.loadingEllipsis') : debugText}
rows={18}
className="w-full font-mono text-xs text-black bg-gray-50 border border-gray-200 rounded-md p-3 resize-none focus:outline-none text-left"
/>
<div className="mt-3 flex items-center justify-between">
<button
onClick={handleCopy}
disabled={loading}
className="inline-flex items-center gap-1.5 rounded-md bg-desert-green px-3 py-1.5 text-sm font-semibold text-white hover:bg-desert-green-dark transition-colors disabled:opacity-50"
>
{copied ? (
<>
<IconCheck className="size-4" />
{t('debugInfo.copied')}
</>
) : (
<>
<IconCopy className="size-4" />
{t('debugInfo.copyToClipboard')}
</>
)}
</button>
<a
href="https://github.com/Crosstalk-Solutions/project-nomad/issues"
target="_blank"
rel="noopener noreferrer"
className="text-sm text-desert-green hover:underline"
>
{t('debugInfo.openGithubIssue')}
</a>
</div>
</StyledModal>
)
}