shinkan-jinkendo/frontend/src/context/OrgInboxContext.jsx
Lars 5cf61289ec
Some checks failed
Deploy Development / deploy (push) Successful in 41s
Test Suite / pytest-backend (push) Failing after 40s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 10s
Test Suite / playwright-tests (push) Successful in 1m3s
feat(P-13): Club-Admin Bearbeitung + Archiv-Trennung in Inbox
Berechtigungen:
- Club-Admins koennen Meldungen zu Vereinsmedien bearbeiten (PATCH + GET-Detail)
- Club-Admins koennen Legal Hold auf Vereinsmedien (visibility != 'official') setzen
- Neue Helfer: _assert_can_manage_report, _assert_can_set_legal_hold_from_report
- set_legal_hold_from_report: Superadmin-Only aufgehoben fuer Vereinsebene

Inbox UI:
- Offene Meldungen (submitted/under_review) im Hauptbereich
- Abgeschlossene Meldungen im kollabierbaren Archiv (standardmaessig zugeklappt)
- Legal-Hold-Button sichtbar fuer Club-Admins bei nicht-offiziellen Medien
- isClubAdmin + isPlatformAdmin aus OrgInboxContext verfuegbar

version: 0.8.93

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 22:15:29 +02:00

134 lines
4.0 KiB
JavaScript

import {
createContext,
useCallback,
useContext,
useEffect,
useMemo,
useState,
} from 'react'
import api from '../utils/api'
import { activeClubMemberships } from '../utils/activeClub'
const OrgInboxContext = createContext(null)
export function canAccessOrgInbox(user) {
if (!user?.id) return false
if (user.role === 'admin' || user.role === 'superadmin') return true
return activeClubMemberships(user.clubs).some((c) => (c.roles || []).includes('club_admin'))
}
function canSeeContentReports(user) {
if (user?.role === 'admin' || user?.role === 'superadmin') return true
return activeClubMemberships(user?.clubs || []).some((c) => (c.roles || []).includes('club_admin'))
}
/** Nach Annahme/Ablehnung: Posteingang-Badges & Widget aktualisieren */
export function notifyOrgInboxChanged() {
window.dispatchEvent(new Event('shinkan:inbox-changed'))
}
export function OrgInboxProvider({ user, children }) {
const [items, setItems] = useState([])
const [contentReports, setContentReports] = useState([])
const [contentReportsError, setContentReportsError] = useState(null)
const canAccess = useMemo(() => canAccessOrgInbox(user), [user])
const canAccessReports = useMemo(() => canSeeContentReports(user), [user])
const refresh = useCallback(async () => {
if (!canAccess) {
setItems([])
} else {
try {
const data = await api.getInboxJoinRequests()
setItems(Array.isArray(data) ? data : [])
} catch {
setItems([])
}
}
if (!canAccessReports) {
setContentReports([])
setContentReportsError(null)
} else {
try {
const data = await api.getInboxContentReports()
setContentReports(Array.isArray(data) ? data : [])
setContentReportsError(null)
} catch (err) {
setContentReports([])
setContentReportsError(err?.message || String(err))
}
}
}, [canAccess, canAccessReports])
useEffect(() => {
if (!canAccess && !canAccessReports) {
setItems([])
setContentReports([])
setContentReportsError(null)
return undefined
}
let cancelled = false
;(async () => {
if (canAccess) {
try {
const data = await api.getInboxJoinRequests()
if (!cancelled) setItems(Array.isArray(data) ? data : [])
} catch {
if (!cancelled) setItems([])
}
}
if (canAccessReports) {
try {
const data = await api.getInboxContentReports()
if (!cancelled) {
setContentReports(Array.isArray(data) ? data : [])
setContentReportsError(null)
}
} catch (err) {
if (!cancelled) {
setContentReports([])
setContentReportsError(err?.message || String(err))
}
}
}
})()
return () => {
cancelled = true
}
}, [canAccess, canAccessReports, user?.id])
useEffect(() => {
const onChange = () => { refresh() }
window.addEventListener('shinkan:inbox-changed', onChange)
return () => window.removeEventListener('shinkan:inbox-changed', onChange)
}, [refresh])
const value = useMemo(
() => ({
inboxJoinRequests: items,
inboxCount: items.length,
contentReports,
contentReportCount: contentReports.filter((r) => r.status === 'submitted').length,
contentReportsError,
refreshOrgInbox: refresh,
canAccessOrgInbox: canAccess,
canAccessContentReports: canAccessReports,
isSuperadmin: user?.role === 'superadmin',
isPlatformAdmin: user?.role === 'admin' || user?.role === 'superadmin',
isClubAdmin: activeClubMemberships(user?.clubs || []).some((c) => (c.roles || []).includes('club_admin')),
}),
[items, contentReports, contentReportsError, refresh, canAccess, canAccessReports, user?.role, user?.clubs]
)
return <OrgInboxContext.Provider value={value}>{children}</OrgInboxContext.Provider>
}
export function useOrgInbox() {
const ctx = useContext(OrgInboxContext)
if (!ctx) {
throw new Error('useOrgInbox must be used within OrgInboxProvider')
}
return ctx
}