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
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>
134 lines
4.0 KiB
JavaScript
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
|
|
}
|