- 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.
122 lines
4.4 KiB
JavaScript
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>
|
|
)
|
|
}
|