mitai-jinkendo/frontend/src/pages/AdminCsvTemplatesPage.jsx
Lars c10da55ec6
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
feat(csv-templates): Introduce CSV template analysis and validation features
- Added a new endpoint for analyzing uploaded CSV files, providing suggestions for field mappings and type conversions.
- Implemented validation for required field targets to ensure all mandatory fields are mapped correctly.
- Enhanced the admin CSV templates interface with new routes and navigation options in the frontend.
- Updated API utility functions to support the new CSV analysis functionality.
- Improved error handling for CSV uploads, including file size and row count checks.
2026-04-10 06:39:41 +02:00

122 lines
4.4 KiB
JavaScript

import { useEffect, useState } from 'react'
import { Link } from 'react-router-dom'
import { ArrowLeft, FileSpreadsheet, Plus, Pencil } from 'lucide-react'
import { api } from '../utils/api'
const MODULE_LABEL = {
nutrition: 'Ernährung',
weight: 'Gewicht',
blood_pressure: 'Blutdruck',
activity: 'Aktivität',
}
export default function AdminCsvTemplatesPage() {
const [templates, setTemplates] = useState([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
const [filterModule, setFilterModule] = useState('')
useEffect(() => {
let ok = true
setLoading(true)
setError(null)
api
.adminListCsvTemplates(filterModule || null)
.then((d) => {
if (ok) setTemplates(d.templates || [])
})
.catch((e) => {
if (ok) setError(e.message)
})
.finally(() => {
if (ok) setLoading(false)
})
return () => {
ok = false
}
}, [filterModule])
return (
<div style={{ padding: '16px 16px 96px', maxWidth: 900, margin: '0 auto' }}>
<Link
to="/admin"
className="btn btn-secondary"
style={{ display: 'inline-flex', alignItems: 'center', gap: 8, marginBottom: 16, textDecoration: 'none' }}
>
<ArrowLeft size={18} /> Admin
</Link>
<h1 className="page-title" style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
<FileSpreadsheet size={26} strokeWidth={2} />
CSV-Import-Vorlagen (System)
</h1>
<p style={{ fontSize: 14, color: 'var(--text2)', lineHeight: 1.55, marginBottom: 20 }}>
Systemweite Vorlagen für den Universal-CSV-Import. Neue Vorlagen entstehen aus einer Beispiel-CSV inkl.
Spaltenzuordnung analog zur Import-Seite.
</p>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 12, alignItems: 'center', marginBottom: 20 }}>
<Link to="/admin/csv-templates/new" className="btn btn-primary" style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
<Plus size={18} /> Neue Vorlage
</Link>
<label style={{ fontSize: 14, color: 'var(--text2)', display: 'flex', alignItems: 'center', gap: 8 }}>
Modul:
<select
className="form-input"
value={filterModule}
onChange={(e) => setFilterModule(e.target.value)}
style={{ minWidth: 160 }}
>
<option value="">Alle</option>
<option value="nutrition">Ernährung</option>
<option value="weight">Gewicht</option>
<option value="blood_pressure">Blutdruck</option>
<option value="activity">Aktivität</option>
</select>
</label>
</div>
{error && (
<div className="card" style={{ padding: 12, borderColor: 'var(--danger)', color: 'var(--danger)', marginBottom: 16 }}>
{error}
</div>
)}
{loading ? (
<div className="spinner" style={{ width: 32, height: 32, margin: 24 }} />
) : (
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
{templates.length === 0 ? (
<div className="card" style={{ padding: 16, color: 'var(--text2)' }}>
Keine Vorlagen. Neue Vorlage legt eine System-Vorlage aus einer CSV an.
</div>
) : (
templates.map((t) => (
<div key={t.id} className="card" style={{ padding: 16 }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 12 }}>
<div>
<div style={{ fontWeight: 600 }}>
{MODULE_LABEL[t.module] || t.module}: {t.mapping_name}
</div>
<div style={{ fontSize: 13, color: 'var(--text2)', marginTop: 6 }}>
{t.description || '—'} · Trenner: <code>{t.delimiter}</code> · Spalten-Signatur:{' '}
{(t.column_signature || []).length} Felder
</div>
</div>
<Link
to={`/admin/csv-templates/${t.id}`}
className="btn btn-secondary"
style={{ display: 'inline-flex', alignItems: 'center', gap: 6, flexShrink: 0 }}
>
<Pencil size={16} /> Bearbeiten
</Link>
</div>
</div>
))
)}
</div>
)}
</div>
)
}