fix: AdminUserRestrictionsPage - show effective values, auto-remove redundant overrides
Major UX improvements: - Display effective value in input (override if set, otherwise tier limit) - Format NULL as "unlimited" (easy to type, no special char needed) - Auto-remove override when value equals tier default - "Zurück" button resets to tier default value - Wider input field (120px) for "unlimited" text This solves: - User can now see and edit current effective values - "unlimited" can be typed and saved - Redundant overrides (value = tier default) are prevented - No more confusion with empty fields vs actual values Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
adfa9ec139
commit
4e592dddc5
|
|
@ -77,13 +77,7 @@ export default function AdminUserRestrictionsPage() {
|
||||||
|
|
||||||
function handleChange(featureId, value) {
|
function handleChange(featureId, value) {
|
||||||
const newChanges = { ...changes }
|
const newChanges = { ...changes }
|
||||||
|
const tierLimit = tierLimits[featureId]
|
||||||
// Empty string means: remove override
|
|
||||||
if (value === '') {
|
|
||||||
newChanges[featureId] = { action: 'remove', tempValue: '' }
|
|
||||||
setChanges(newChanges)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse value (EXACTLY like TierLimitsPage)
|
// Parse value (EXACTLY like TierLimitsPage)
|
||||||
let parsedValue = null
|
let parsedValue = null
|
||||||
|
|
@ -91,6 +85,8 @@ export default function AdminUserRestrictionsPage() {
|
||||||
parsedValue = null // unlimited
|
parsedValue = null // unlimited
|
||||||
} else if (value === '0' || value === 'disabled') {
|
} else if (value === '0' || value === 'disabled') {
|
||||||
parsedValue = 0 // disabled
|
parsedValue = 0 // disabled
|
||||||
|
} else if (value === '') {
|
||||||
|
parsedValue = null // empty → unlimited
|
||||||
} else {
|
} else {
|
||||||
const num = parseInt(value)
|
const num = parseInt(value)
|
||||||
if (!isNaN(num) && num >= 0) {
|
if (!isNaN(num) && num >= 0) {
|
||||||
|
|
@ -100,7 +96,14 @@ export default function AdminUserRestrictionsPage() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newChanges[featureId] = { action: 'set', value: parsedValue, tempValue: value }
|
// Check if value equals tier limit → remove override
|
||||||
|
if (parsedValue === tierLimit) {
|
||||||
|
newChanges[featureId] = { action: 'remove', tempValue: value }
|
||||||
|
} else {
|
||||||
|
// Different from tier default → set override
|
||||||
|
newChanges[featureId] = { action: 'set', value: parsedValue, tempValue: value }
|
||||||
|
}
|
||||||
|
|
||||||
setChanges(newChanges)
|
setChanges(newChanges)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -175,22 +178,30 @@ export default function AdminUserRestrictionsPage() {
|
||||||
// Check pending changes first
|
// Check pending changes first
|
||||||
if (featureId in changes) {
|
if (featureId in changes) {
|
||||||
const change = changes[featureId]
|
const change = changes[featureId]
|
||||||
if (change.action === 'remove') return ''
|
if (change.action === 'remove') {
|
||||||
|
// Returning to tier default
|
||||||
|
return formatValue(tierLimits[featureId])
|
||||||
|
}
|
||||||
if (change.action === 'set') {
|
if (change.action === 'set') {
|
||||||
// Use tempValue for display if available, otherwise format the value
|
// Use tempValue for display if available, otherwise format the value
|
||||||
return change.tempValue !== undefined ? change.tempValue : formatValue(change.value)
|
return change.tempValue !== undefined ? change.tempValue : formatValue(change.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show existing restriction value (or empty if no restriction)
|
// Show override if exists, otherwise tier limit (= effective value)
|
||||||
const restriction = restrictions.find(r => r.feature_id === featureId)
|
const restriction = restrictions.find(r => r.feature_id === featureId)
|
||||||
if (!restriction) return '' // No override = empty input
|
if (restriction) {
|
||||||
return formatValue(restriction.limit_value)
|
return formatValue(restriction.limit_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// No override: show tier limit as default
|
||||||
|
return formatValue(tierLimits[featureId])
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatValue(val) {
|
function formatValue(val) {
|
||||||
if (val === '' || val === null || val === undefined) return ''
|
if (val === null || val === undefined) return 'unlimited'
|
||||||
if (val === '∞' || val === 'unlimited') return '∞'
|
if (val === '' ) return ''
|
||||||
|
if (val === '∞' || val === 'unlimited') return 'unlimited'
|
||||||
if (val === 0 || val === '0') return '0'
|
if (val === 0 || val === '0') return '0'
|
||||||
return val.toString()
|
return val.toString()
|
||||||
}
|
}
|
||||||
|
|
@ -258,9 +269,8 @@ export default function AdminUserRestrictionsPage() {
|
||||||
}}>
|
}}>
|
||||||
<AlertCircle size={16} style={{ marginTop: 2, flexShrink: 0 }} />
|
<AlertCircle size={16} style={{ marginTop: 2, flexShrink: 0 }} />
|
||||||
<div>
|
<div>
|
||||||
<strong>Hinweis:</strong> User-Overrides überschreiben Tier-Limits.
|
<strong>Hinweis:</strong> Felder zeigen effektive Werte (Override falls gesetzt, sonst Tier-Standard).
|
||||||
Leere Felder = kein Override (User nutzt Tier-Standard).
|
Wert ändern → Override wird gesetzt. Wert = Tier-Standard → Override wird entfernt.
|
||||||
Wert eingeben = Override setzen.
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -456,9 +466,9 @@ export default function AdminUserRestrictionsPage() {
|
||||||
type="text"
|
type="text"
|
||||||
value={displayValue}
|
value={displayValue}
|
||||||
onChange={(e) => handleChange(feature.id, e.target.value)}
|
onChange={(e) => handleChange(feature.id, e.target.value)}
|
||||||
placeholder="∞"
|
placeholder=""
|
||||||
style={{
|
style={{
|
||||||
width: '100px',
|
width: '120px',
|
||||||
padding: '6px 8px',
|
padding: '6px 8px',
|
||||||
border: `1.5px solid ${changed ? 'var(--accent)' : override ? 'var(--accent)' : 'var(--border)'}`,
|
border: `1.5px solid ${changed ? 'var(--accent)' : override ? 'var(--accent)' : 'var(--border)'}`,
|
||||||
borderRadius: 6,
|
borderRadius: 6,
|
||||||
|
|
@ -467,7 +477,7 @@ export default function AdminUserRestrictionsPage() {
|
||||||
fontWeight: override || changed ? 600 : 400,
|
fontWeight: override || changed ? 600 : 400,
|
||||||
background: override || changed ? 'var(--accent-light)' : 'var(--bg)',
|
background: override || changed ? 'var(--accent-light)' : 'var(--bg)',
|
||||||
color: displayValue === '0' ? 'var(--danger)' :
|
color: displayValue === '0' ? 'var(--danger)' :
|
||||||
displayValue === '∞' ? 'var(--accent)' : 'var(--text1)'
|
displayValue === 'unlimited' ? 'var(--accent)' : 'var(--text1)'
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
@ -477,7 +487,11 @@ export default function AdminUserRestrictionsPage() {
|
||||||
<td style={{ padding: '12px 16px', textAlign: 'right' }}>
|
<td style={{ padding: '12px 16px', textAlign: 'right' }}>
|
||||||
<button
|
<button
|
||||||
className="btn btn-secondary"
|
className="btn btn-secondary"
|
||||||
onClick={() => handleChange(feature.id, '')}
|
onClick={() => {
|
||||||
|
// Reset to tier default
|
||||||
|
const tierValue = tierLimits[feature.id]
|
||||||
|
handleChange(feature.id, formatValue(tierValue))
|
||||||
|
}}
|
||||||
disabled={!override}
|
disabled={!override}
|
||||||
style={{
|
style={{
|
||||||
padding: '4px 8px',
|
padding: '4px 8px',
|
||||||
|
|
@ -504,12 +518,16 @@ export default function AdminUserRestrictionsPage() {
|
||||||
marginTop: 16, padding: 12, background: 'var(--surface2)',
|
marginTop: 16, padding: 12, background: 'var(--surface2)',
|
||||||
borderRadius: 8, fontSize: 12, color: 'var(--text3)'
|
borderRadius: 8, fontSize: 12, color: 'var(--text3)'
|
||||||
}}>
|
}}>
|
||||||
<strong>Eingabe (Count-Features):</strong>
|
<strong>Eingabe:</strong>
|
||||||
<div style={{ marginTop: 8, display: 'flex', gap: 16, flexWrap: 'wrap' }}>
|
<div style={{ marginTop: 8, display: 'flex', gap: 16, flexWrap: 'wrap' }}>
|
||||||
<span><strong style={{ color: 'var(--accent)' }}>∞</strong> oder <strong>unlimited</strong> = Unbegrenzt</span>
|
<span><strong>unlimited</strong> = Unbegrenzt</span>
|
||||||
<span><strong style={{ color: 'var(--danger)' }}>0</strong> = Feature deaktiviert</span>
|
<span><strong style={{ color: 'var(--danger)' }}>0</strong> = Feature deaktiviert</span>
|
||||||
<span><strong>1+</strong> = Limit-Wert</span>
|
<span><strong>1+</strong> = Limit-Wert</span>
|
||||||
<span><strong>Leer</strong> = kein Override (Tier-Standard)</span>
|
</div>
|
||||||
|
<div style={{ marginTop: 8, fontSize: 11, opacity: 0.8 }}>
|
||||||
|
• Feld zeigt effektiven Wert (Override falls gesetzt, sonst Tier-Standard)<br />
|
||||||
|
• Wert ändern → Override wird gesetzt<br />
|
||||||
|
• Wert = Tier-Standard → Override wird entfernt
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user