Refine admin workflows and team access

This commit is contained in:
AzuTear
2026-06-26 18:09:29 +02:00
parent b7804e10ea
commit 8b69dfbafb
71 changed files with 5066 additions and 751 deletions
@@ -1,4 +1,4 @@
import { computed, onMounted, reactive, ref } from 'vue'
import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
import { ApiRequestError, api } from '../../lib/api'
import type { AdminTeamMember, AdminTeamPermission, AdminTeamRole } from '../../types/awards'
@@ -17,9 +17,13 @@ const emptyMemberForm = (): TeamMemberForm => ({
isActive: true,
})
const TEAM_PRESENCE_REFRESH_MS = 30_000
export function useAdminTeamManager() {
const loading = ref(true)
const saving = ref(false)
const refreshingPresence = ref(false)
const lastPresenceRefreshAt = ref<Date | null>(null)
const errorMessage = ref('')
const successMessage = ref('')
const generatedPassword = ref('')
@@ -60,18 +64,34 @@ export function useAdminTeamManager() {
savedRoleSnapshot.value = JSON.stringify(rolePermissionDrafts.value)
}
async function loadTeam() {
loading.value = true
resetMessages()
async function loadTeam(options: { silent?: boolean } = {}) {
const silent = options.silent === true
const showLoading = !silent || members.value.length === 0
if (showLoading) {
loading.value = true
} else {
refreshingPresence.value = true
}
if (!silent) {
resetMessages()
}
try {
applyTeamResponse(await api.getAdminTeam())
lastPresenceRefreshAt.value = new Date()
} catch (error) {
errorMessage.value = error instanceof ApiRequestError
? error.message
: 'Team-Daten konnten nicht geladen werden.'
if (!silent) {
errorMessage.value = error instanceof ApiRequestError
? error.message
: 'Team-Daten konnten nicht geladen werden.'
}
} finally {
loading.value = false
if (showLoading) {
loading.value = false
}
refreshingPresence.value = false
}
}
@@ -123,7 +143,7 @@ export function useAdminTeamManager() {
displayName: memberForm.displayName,
role: memberForm.role,
})
await loadTeam()
await loadTeam({ silent: true })
generatedPassword.value = result.generatedPassword
generatedPasswordLogin.value = memberForm.login
successMessage.value = 'Team-Login wurde erstellt. Das temporäre Passwort ist nur jetzt sichtbar.'
@@ -134,7 +154,7 @@ export function useAdminTeamManager() {
role: memberForm.role,
isActive: memberForm.isActive,
})
await loadTeam()
await loadTeam({ silent: true })
successMessage.value = 'Team-Mitglied wurde gespeichert.'
}
return true
@@ -156,7 +176,7 @@ export function useAdminTeamManager() {
try {
const result = await api.resetAdminTeamMemberPassword(member.id)
await loadTeam()
await loadTeam({ silent: true })
generatedPassword.value = result.generatedPassword
generatedPasswordLogin.value = member.login
successMessage.value = 'Passwort wurde zurückgesetzt. Das Mitglied muss es beim nächsten Login ändern.'
@@ -190,7 +210,7 @@ export function useAdminTeamManager() {
if (editingMemberId.value === member.id) {
startCreateMember()
}
await loadTeam()
await loadTeam({ silent: true })
successMessage.value = 'Team-Mitglied wurde gelöscht.'
} catch (error) {
errorMessage.value = error instanceof ApiRequestError
@@ -244,11 +264,29 @@ export function useAdminTeamManager() {
}
}
onMounted(loadTeam)
let presenceRefreshTimer: ReturnType<typeof window.setInterval> | null = null
onMounted(() => {
void loadTeam()
presenceRefreshTimer = window.setInterval(() => {
if (!saving.value) {
void loadTeam({ silent: true })
}
}, TEAM_PRESENCE_REFRESH_MS)
})
onBeforeUnmount(() => {
if (presenceRefreshTimer) {
window.clearInterval(presenceRefreshTimer)
presenceRefreshTimer = null
}
})
return {
loading,
saving,
refreshingPresence,
lastPresenceRefreshAt,
errorMessage,
successMessage,
generatedPassword,