Membership-System und Bug Fixing (inkl. Nutrition) #8
|
|
@ -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() {
|
|||
<table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
|
||||
<thead>
|
||||
<tr style={{ background: 'var(--surface2)' }}>
|
||||
<th style={{ textAlign: 'left', padding: '12px 16px', fontWeight: 600, width: '40%' }}>
|
||||
<th style={{ textAlign: 'left', padding: '12px 16px', fontWeight: 600 }}>
|
||||
Feature
|
||||
</th>
|
||||
<th style={{ textAlign: 'center', padding: '12px 16px', fontWeight: 600, width: '30%' }}>
|
||||
<th style={{ textAlign: 'center', padding: '12px 16px', fontWeight: 600 }}>
|
||||
Tier-Limit
|
||||
</th>
|
||||
<th style={{ textAlign: 'center', padding: '12px 16px', fontWeight: 600 }}>
|
||||
Override-Wert
|
||||
</th>
|
||||
<th style={{ textAlign: 'right', padding: '12px 16px', fontWeight: 600, width: '30%' }}>
|
||||
Status
|
||||
<th style={{ textAlign: 'right', padding: '12px 16px', fontWeight: 600 }}>
|
||||
Aktion
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -328,7 +344,7 @@ export default function AdminUserRestrictionsPage() {
|
|||
<>
|
||||
{/* Category Header */}
|
||||
<tr key={`cat-${category}`} style={{ background: 'var(--accent-light)' }}>
|
||||
<td colSpan={3} style={{
|
||||
<td colSpan={4} style={{
|
||||
padding: '8px 16px', fontWeight: 600, fontSize: 11,
|
||||
textTransform: 'uppercase', letterSpacing: '0.5px',
|
||||
color: 'var(--accent-dark)'
|
||||
|
|
@ -357,6 +373,24 @@ export default function AdminUserRestrictionsPage() {
|
|||
</div>
|
||||
</td>
|
||||
|
||||
{/* Tier-Limit */}
|
||||
<td style={{ padding: '12px 16px', textAlign: 'center' }}>
|
||||
{feature.limit_type === 'boolean' ? (
|
||||
<span style={{
|
||||
padding: '6px 12px', borderRadius: 20,
|
||||
background: tierLimits[feature.id] !== 0 ? 'var(--accent-light)' : 'var(--surface2)',
|
||||
color: tierLimits[feature.id] !== 0 ? 'var(--accent-dark)' : 'var(--text3)',
|
||||
fontSize: 12, fontWeight: 600
|
||||
}}>
|
||||
{tierLimits[feature.id] !== 0 ? '✓ AN' : '✗ AUS'}
|
||||
</span>
|
||||
) : (
|
||||
<span style={{ fontWeight: 500, color: 'var(--text2)' }}>
|
||||
{tierLimits[feature.id] === null ? '∞' : tierLimits[feature.id]}
|
||||
</span>
|
||||
)}
|
||||
</td>
|
||||
|
||||
{/* Override Input */}
|
||||
<td style={{ padding: '12px 16px', textAlign: 'center' }}>
|
||||
{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)'
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</td>
|
||||
|
||||
{/* Status */}
|
||||
{/* Action */}
|
||||
<td style={{ padding: '12px 16px', textAlign: 'right' }}>
|
||||
{override ? (
|
||||
<span style={{
|
||||
padding: '4px 8px', borderRadius: 4, fontSize: 11,
|
||||
background: 'var(--accent-light)', color: 'var(--accent-dark)',
|
||||
fontWeight: 600
|
||||
}}>
|
||||
✓ Override aktiv
|
||||
</span>
|
||||
) : (
|
||||
<span style={{ fontSize: 11, color: 'var(--text3)' }}>
|
||||
Tier-Standard
|
||||
</span>
|
||||
{override && (
|
||||
<button
|
||||
className="btn btn-secondary"
|
||||
onClick={() => handleChange(feature.id, '')}
|
||||
style={{ padding: '4px 8px', fontSize: 11 }}
|
||||
>
|
||||
↺ Zurück zu Standard
|
||||
</button>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
|
|
@ -436,7 +466,7 @@ export default function AdminUserRestrictionsPage() {
|
|||
disabled={!hasChanges || saving}
|
||||
style={{ flex: 1 }}
|
||||
>
|
||||
<RotateCcw size={14} /> Zurücksetzen
|
||||
<X size={14} /> Abbrechen
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-primary"
|
||||
|
|
@ -444,7 +474,7 @@ export default function AdminUserRestrictionsPage() {
|
|||
disabled={!hasChanges || saving}
|
||||
style={{ flex: 2 }}
|
||||
>
|
||||
{saving ? 'Speichern...' : hasChanges ? `${Object.keys(changes).length} Änderung(en) speichern` : 'Speichern'}
|
||||
{saving ? 'Speichern...' : hasChanges ? `${Object.keys(changes).length} Änderung(en) speichern` : 'Keine Änderungen'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user