shinkan-jinkendo/frontend/src/context/OrgInboxContext.jsx
Lars 37785135b1
Some checks failed
Deploy Development / deploy (push) Successful in 47s
Test Suite / pytest-backend (push) Successful in 42s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 13s
Test Suite / k6 /health Baseline (push) Successful in 33s
Test Suite / playwright-tests (push) Failing after 1m21s
Refactor Org Inbox Context and Enhance Club Creation Management
- Updated the OrgInboxContext to include handling for club creation requests, allowing for better management of inbox items.
- Refactored components to utilize the new `canShowInboxNav` and `canAccessClubCreationInbox` flags for improved access control.
- Enhanced the InboxPage to display club creation requests with appropriate actions for approval and rejection.
- Updated the DashboardOrgInboxWidget to show both club creation and join requests, improving the user interface for managing inbox items.
2026-06-07 07:18:43 +02:00

200 lines
6.2 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'))
}
/** Gründungsanträge freigeben — aktuell nur Superadmin (platform.club_creation.approve). */
export function canAccessClubCreationInbox(user) {
return user?.role === 'superadmin'
}
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'))
}
/** Eine konsistente Ladepfad-Logik für Join-Requests + Content-Reports (ein Codepfad für Mount + refresh). */
async function fetchOrgInboxSnapshot(canAccess, canAccessReports, canAccessClubCreation) {
const out = {
items: [],
clubCreationRequests: [],
contentReports: [],
contentReportsError: null,
}
if (canAccess) {
try {
const data = await api.getInboxJoinRequests()
out.items = Array.isArray(data) ? data : []
} catch {
out.items = []
}
}
if (canAccessClubCreation) {
try {
const data = await api.listAdminClubCreationRequests()
out.clubCreationRequests = Array.isArray(data) ? data : []
} catch {
out.clubCreationRequests = []
}
}
if (canAccessReports) {
try {
const data = await api.getInboxContentReports()
out.contentReports = Array.isArray(data) ? data : []
} catch (err) {
out.contentReports = []
out.contentReportsError = err?.message || String(err)
}
}
return out
}
export function OrgInboxProvider({ user, children }) {
const [items, setItems] = useState([])
const [clubCreationRequests, setClubCreationRequests] = useState([])
const [contentReports, setContentReports] = useState([])
const [contentReportsError, setContentReportsError] = useState(null)
const canAccess = useMemo(() => canAccessOrgInbox(user), [user])
const canAccessReports = useMemo(() => canSeeContentReports(user), [user])
const canAccessClubCreation = useMemo(() => canAccessClubCreationInbox(user), [user])
const hasInboxAccess = canAccess || canAccessReports || canAccessClubCreation
const refresh = useCallback(async () => {
if (!hasInboxAccess) {
setItems([])
setClubCreationRequests([])
setContentReports([])
setContentReportsError(null)
return
}
const snap = await fetchOrgInboxSnapshot(canAccess, canAccessReports, canAccessClubCreation)
setItems(snap.items)
setClubCreationRequests(snap.clubCreationRequests)
setContentReports(snap.contentReports)
setContentReportsError(canAccessReports ? snap.contentReportsError : null)
}, [hasInboxAccess, canAccess, canAccessReports, canAccessClubCreation])
useEffect(() => {
if (!hasInboxAccess) {
setItems([])
setClubCreationRequests([])
setContentReports([])
setContentReportsError(null)
return undefined
}
let cancelled = false
let idleId = null
let timeoutId = null
const load = async () => {
const snap = await fetchOrgInboxSnapshot(canAccess, canAccessReports, canAccessClubCreation)
if (cancelled) return
setItems(snap.items)
setClubCreationRequests(snap.clubCreationRequests)
setContentReports(snap.contentReports)
setContentReportsError(canAccessReports ? snap.contentReportsError : null)
}
const schedule = () => {
if (cancelled) return
if (typeof window.requestIdleCallback === 'function') {
idleId = window.requestIdleCallback(
() => {
idleId = null
void load()
},
{ timeout: 1500 },
)
} else {
timeoutId = window.setTimeout(() => {
timeoutId = null
void load()
}, 0)
}
}
schedule()
return () => {
cancelled = true
if (idleId != null && typeof window.cancelIdleCallback === 'function') {
window.cancelIdleCallback(idleId)
}
if (timeoutId != null) window.clearTimeout(timeoutId)
}
}, [hasInboxAccess, canAccess, canAccessReports, canAccessClubCreation, user?.id])
useEffect(() => {
const onChange = () => { refresh() }
window.addEventListener('shinkan:inbox-changed', onChange)
return () => window.removeEventListener('shinkan:inbox-changed', onChange)
}, [refresh])
const clubCreationCount = clubCreationRequests.length
const joinCount = items.length
const value = useMemo(
() => ({
inboxJoinRequests: items,
inboxClubCreationRequests: clubCreationRequests,
clubCreationRequestCount: clubCreationCount,
inboxCount: joinCount + clubCreationCount,
contentReports,
contentReportCount: contentReports.filter((r) => r.status === 'submitted').length,
contentReportsError,
refreshOrgInbox: refresh,
canAccessOrgInbox: canAccess,
canAccessContentReports: canAccessReports,
canAccessClubCreationInbox: canAccessClubCreation,
canShowInboxNav: hasInboxAccess,
isSuperadmin: user?.role === 'superadmin',
isPlatformAdmin: user?.role === 'admin' || user?.role === 'superadmin',
isClubAdmin: activeClubMemberships(user?.clubs || []).some((c) => (c.roles || []).includes('club_admin')),
}),
[
items,
clubCreationRequests,
clubCreationCount,
joinCount,
contentReports,
contentReportsError,
refresh,
canAccess,
canAccessReports,
canAccessClubCreation,
hasInboxAccess,
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
}