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
- 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.
200 lines
6.2 KiB
JavaScript
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
|
|
}
|