From 5ef6a80a1fd36a0b77dd6cb2ad908c6239218351 Mon Sep 17 00:00:00 2001 From: Lars Date: Fri, 20 Mar 2026 08:13:11 +0100 Subject: [PATCH] fix: add tier limits display and improve buttons in AdminUserRestrictionsPage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added tier limits column: - Shows current tier-limit value for each feature - Loads from tier-limits matrix based on user's tier - Visual display for boolean (✓ AN / ✗ AUS) and count features - Clear comparison: Tier-Limit vs Override-Wert Added per-feature reset button: - "↺ Zurück zu Standard" button per feature - Only shown when override exists - Removes override with single click Improved bottom bar buttons: - Renamed "Zurücksetzen" to "Abbrechen" (clearer) - Always visible (not hidden when no changes) - Disabled state when no changes - Shows "Keine Änderungen" when nothing to save Better UX: - Tier-Limit column shows what user gets without override - Override input highlighted when active (accent-light background) - Clear action buttons per row - Global save/cancel at bottom Co-Authored-By: Claude Opus 4.6 --- .../src/pages/AdminUserRestrictionsPage.jsx | 84 +++++++++++++------ 1 file changed, 57 insertions(+), 27 deletions(-) diff --git a/frontend/src/pages/AdminUserRestrictionsPage.jsx b/frontend/src/pages/AdminUserRestrictionsPage.jsx index a27be09..55cedb6 100644 --- a/frontend/src/pages/AdminUserRestrictionsPage.jsx +++ b/frontend/src/pages/AdminUserRestrictionsPage.jsx @@ -11,6 +11,7 @@ export default function AdminUserRestrictionsPage() { const [selectedUserId, setSelectedUserId] = useState('') const [selectedUser, setSelectedUser] = useState(null) const [restrictions, setRestrictions] = useState([]) + const [tierLimits, setTierLimits] = useState({}) const [changes, setChanges] = useState({}) const [saving, setSaving] = useState(false) @@ -47,12 +48,24 @@ export default function AdminUserRestrictionsPage() { async function loadUserData(userId) { try { - const [user, restrictionsData] = await Promise.all([ + const [user, restrictionsData, limitsMatrix] = await Promise.all([ api.adminListProfiles().then(users => users.find(u => u.id === userId)), - api.listUserRestrictions(userId) + api.listUserRestrictions(userId), + api.getTierLimitsMatrix() ]) + setSelectedUser(user) setRestrictions(restrictionsData) + + // Build tier limits lookup for this user's tier + const userTier = user.tier || 'free' + const limits = {} + features.forEach(feature => { + const key = `${userTier}:${feature.id}` + limits[feature.id] = limitsMatrix.limits[key] ?? feature.default_limit + }) + setTierLimits(limits) + setChanges({}) setError('') setSuccess('') @@ -312,14 +325,17 @@ export default function AdminUserRestrictionsPage() { - - + - @@ -328,7 +344,7 @@ export default function AdminUserRestrictionsPage() { <> {/* Category Header */} - + {/* Tier-Limit */} + + {/* Override Input */} - {/* Status */} + {/* Action */} @@ -436,7 +466,7 @@ export default function AdminUserRestrictionsPage() { disabled={!hasChanges || saving} style={{ flex: 1 }} > - Zurücksetzen + Abbrechen
+ Feature + + Tier-Limit + Override-Wert - Status + + Aktion
+ {feature.limit_type === 'boolean' ? ( + + {tierLimits[feature.id] !== 0 ? '✓ AN' : '✗ AUS'} + + ) : ( + + {tierLimits[feature.id] === null ? '∞' : tierLimits[feature.id]} + + )} + {feature.limit_type === 'boolean' ? ( @@ -382,36 +416,32 @@ export default function AdminUserRestrictionsPage() { type="text" value={displayValue} onChange={(e) => handleChange(feature.id, e.target.value)} - placeholder="leer = Tier-Standard" + placeholder={override ? "Wert..." : ""} style={{ - width: '140px', + width: '100px', padding: '6px 8px', - border: `1.5px solid ${changed ? 'var(--accent)' : 'var(--border)'}`, + border: `1.5px solid ${changed ? 'var(--accent)' : override ? 'var(--accent)' : 'var(--border)'}`, borderRadius: 6, textAlign: 'center', fontSize: 13, - fontWeight: changed ? 600 : 400, - background: 'var(--bg)', + fontWeight: override || changed ? 600 : 400, + background: override ? 'var(--accent-light)' : 'var(--bg)', color: displayValue === 0 || displayValue === '0' ? 'var(--danger)' : 'var(--text1)' }} /> )} - {override ? ( - - ✓ Override aktiv - - ) : ( - - Tier-Standard - + {override && ( + )}