refactor: improve AdminFeaturesPage form layout and UX
Layout improvements: - Labels now above inputs (not beside) - Inputs use full width for better readability - Better spacing and visual hierarchy Field changes: - Removed "Einheit" field (unused, confusing) - "Sortierung" renamed to "Anzeigereihenfolge" with help text - Added help text under inputs for clarity Conditional rendering: - Boolean features: hide Reset-Periode and Standard-Limit - Show info box explaining Boolean features - Count features: show all relevant fields Better UX: - Clear explanations what each field does - Visual feedback for different limit types - Cleaner, more focused interface Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
69b6f38c89
commit
bc4db19190
|
|
@ -12,7 +12,6 @@ export default function AdminFeaturesPage() {
|
|||
name: '',
|
||||
category: 'data',
|
||||
description: '',
|
||||
unit: 'count',
|
||||
limit_type: 'count',
|
||||
default_limit: '',
|
||||
reset_period: 'never',
|
||||
|
|
@ -43,7 +42,6 @@ export default function AdminFeaturesPage() {
|
|||
name: '',
|
||||
category: 'data',
|
||||
description: '',
|
||||
unit: 'count',
|
||||
limit_type: 'count',
|
||||
default_limit: '',
|
||||
reset_period: 'never',
|
||||
|
|
@ -59,7 +57,6 @@ export default function AdminFeaturesPage() {
|
|||
name: feature.name,
|
||||
category: feature.category,
|
||||
description: feature.description || '',
|
||||
unit: feature.unit || 'count',
|
||||
limit_type: feature.limit_type,
|
||||
default_limit: feature.default_limit === null ? '' : feature.default_limit,
|
||||
reset_period: feature.reset_period,
|
||||
|
|
@ -84,7 +81,6 @@ export default function AdminFeaturesPage() {
|
|||
name: formData.name.trim(),
|
||||
category: formData.category,
|
||||
description: formData.description.trim(),
|
||||
unit: formData.unit,
|
||||
limit_type: formData.limit_type,
|
||||
default_limit: formData.default_limit === '' ? null : parseInt(formData.default_limit),
|
||||
reset_period: formData.reset_period,
|
||||
|
|
@ -189,35 +185,63 @@ export default function AdminFeaturesPage() {
|
|||
</button>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gap: 12 }}>
|
||||
<div style={{ display: 'grid', gap: 16 }}>
|
||||
{/* Feature ID (read-only) */}
|
||||
<div className="form-row">
|
||||
<label className="form-label">Feature ID</label>
|
||||
<div>
|
||||
<label className="form-label" style={{ display: 'block', marginBottom: 6 }}>
|
||||
Feature ID
|
||||
</label>
|
||||
<input
|
||||
className="form-input"
|
||||
value={editingId}
|
||||
disabled
|
||||
style={{ background: 'var(--surface2)', color: 'var(--text3)', cursor: 'not-allowed' }}
|
||||
style={{
|
||||
width: '100%',
|
||||
background: 'var(--surface2)',
|
||||
color: 'var(--text3)',
|
||||
cursor: 'not-allowed',
|
||||
fontFamily: 'monospace'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Name */}
|
||||
<div className="form-row">
|
||||
<label className="form-label">Name *</label>
|
||||
<div>
|
||||
<label className="form-label" style={{ display: 'block', marginBottom: 6 }}>
|
||||
Name *
|
||||
</label>
|
||||
<input
|
||||
className="form-input"
|
||||
style={{ width: '100%' }}
|
||||
value={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
placeholder="z.B. Gewichtseinträge"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
<div>
|
||||
<label className="form-label" style={{ display: 'block', marginBottom: 6 }}>
|
||||
Beschreibung (optional)
|
||||
</label>
|
||||
<input
|
||||
className="form-input"
|
||||
style={{ width: '100%' }}
|
||||
value={formData.description}
|
||||
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
|
||||
placeholder="Kurze Erklärung was dieses Feature limitiert"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Category + Limit Type */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
|
||||
<div className="form-row">
|
||||
<label className="form-label">Kategorie</label>
|
||||
<div>
|
||||
<label className="form-label" style={{ display: 'block', marginBottom: 6 }}>
|
||||
Kategorie
|
||||
</label>
|
||||
<select
|
||||
className="form-input"
|
||||
style={{ width: '100%' }}
|
||||
value={formData.category}
|
||||
onChange={(e) => setFormData({ ...formData, category: e.target.value })}
|
||||
>
|
||||
|
|
@ -227,10 +251,13 @@ export default function AdminFeaturesPage() {
|
|||
</select>
|
||||
</div>
|
||||
|
||||
<div className="form-row">
|
||||
<label className="form-label">Limit-Typ</label>
|
||||
<div>
|
||||
<label className="form-label" style={{ display: 'block', marginBottom: 6 }}>
|
||||
Limit-Typ
|
||||
</label>
|
||||
<select
|
||||
className="form-input"
|
||||
style={{ width: '100%' }}
|
||||
value={formData.limit_type}
|
||||
onChange={(e) => setFormData({ ...formData, limit_type: e.target.value })}
|
||||
>
|
||||
|
|
@ -241,33 +268,17 @@ export default function AdminFeaturesPage() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
<div className="form-row">
|
||||
<label className="form-label">Beschreibung</label>
|
||||
<input
|
||||
className="form-input"
|
||||
value={formData.description}
|
||||
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
|
||||
placeholder="Optionale Beschreibung"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Unit + Reset Period */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
|
||||
<div className="form-row">
|
||||
<label className="form-label">Einheit</label>
|
||||
<input
|
||||
className="form-input"
|
||||
value={formData.unit}
|
||||
onChange={(e) => setFormData({ ...formData, unit: e.target.value })}
|
||||
placeholder="z.B. count, calls"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="form-row">
|
||||
<label className="form-label">Reset-Periode</label>
|
||||
{/* Count-specific fields (only for limit_type='count') */}
|
||||
{formData.limit_type === 'count' && (
|
||||
<>
|
||||
{/* Reset Period */}
|
||||
<div>
|
||||
<label className="form-label" style={{ display: 'block', marginBottom: 6 }}>
|
||||
Reset-Periode
|
||||
</label>
|
||||
<select
|
||||
className="form-input"
|
||||
style={{ width: '100%' }}
|
||||
value={formData.reset_period}
|
||||
onChange={(e) => setFormData({ ...formData, reset_period: e.target.value })}
|
||||
>
|
||||
|
|
@ -275,38 +286,61 @@ export default function AdminFeaturesPage() {
|
|||
<option key={o.value} value={o.value}>{o.label}</option>
|
||||
))}
|
||||
</select>
|
||||
<div style={{ fontSize: 11, color: 'var(--text3)', marginTop: 4 }}>
|
||||
Wann wird der Nutzungszähler zurückgesetzt?
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Default Limit + Sort Order */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
|
||||
<div className="form-row">
|
||||
<label className="form-label">Standard-Limit</label>
|
||||
{/* Default Limit */}
|
||||
<div>
|
||||
<label className="form-label" style={{ display: 'block', marginBottom: 6 }}>
|
||||
Standard-Limit
|
||||
</label>
|
||||
<input
|
||||
className="form-input"
|
||||
style={{ width: '100%' }}
|
||||
type="number"
|
||||
value={formData.default_limit}
|
||||
onChange={(e) => setFormData({ ...formData, default_limit: e.target.value })}
|
||||
placeholder="Leer = unbegrenzt"
|
||||
/>
|
||||
<span className="form-unit" style={{ fontSize: 11, color: 'var(--text3)' }}>
|
||||
Fallback wenn kein Tier-Limit gesetzt
|
||||
</span>
|
||||
<div style={{ fontSize: 11, color: 'var(--text3)', marginTop: 4 }}>
|
||||
Fallback-Wert wenn kein Tier-spezifisches Limit gesetzt ist
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="form-row">
|
||||
<label className="form-label">Sortierung</label>
|
||||
{/* Boolean info */}
|
||||
{formData.limit_type === 'boolean' && (
|
||||
<div style={{
|
||||
padding: 12, background: 'var(--accent-light)', borderRadius: 8,
|
||||
fontSize: 12, color: 'var(--accent-dark)'
|
||||
}}>
|
||||
<strong>Boolean-Feature:</strong> Ist entweder verfügbar (AN) oder nicht verfügbar (AUS).
|
||||
Keine Zähler oder Reset-Perioden notwendig.
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Sort Order */}
|
||||
<div>
|
||||
<label className="form-label" style={{ display: 'block', marginBottom: 6 }}>
|
||||
Anzeigereihenfolge
|
||||
</label>
|
||||
<input
|
||||
className="form-input"
|
||||
style={{ width: '100%' }}
|
||||
type="number"
|
||||
value={formData.sort_order}
|
||||
onChange={(e) => setFormData({ ...formData, sort_order: parseInt(e.target.value) || 50 })}
|
||||
/>
|
||||
<div style={{ fontSize: 11, color: 'var(--text3)', marginTop: 4 }}>
|
||||
Niedrigere Werte erscheinen weiter oben in Listen (Standard: 50)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Checkboxes */}
|
||||
<div style={{ display: 'flex', gap: 16 }}>
|
||||
<div style={{ display: 'flex', gap: 16, paddingTop: 8 }}>
|
||||
<label style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 13 }}>
|
||||
<input
|
||||
type="checkbox"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user