import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue' import { ApiRequestError, api } from '../../lib/api' import type { AdminTeamMember, AdminTeamPermission, AdminTeamRole } from '../../types/awards' export interface TeamMemberForm { login: string displayName: string role: string isActive: boolean } const emptyMemberForm = (): TeamMemberForm => ({ login: '', displayName: '', role: 'member', 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(null) const errorMessage = ref('') const successMessage = ref('') const generatedPassword = ref('') const generatedPasswordLogin = ref('') const confirmDeleteMemberId = ref(null) const members = ref([]) const roles = ref([]) const permissions = ref([]) const editingMemberId = ref(null) const rolePermissionDrafts = ref>({}) const savedRoleSnapshot = ref('') const memberForm = reactive(emptyMemberForm()) const activeMembers = computed(() => members.value.filter((member) => member.isActive).length) const pendingPasswordChanges = computed(() => members.value.filter((member) => member.mustChangePassword).length) const roleOptions = computed(() => roles.value.map((role) => ({ value: role.key, label: role.label }))) const permissionGroups = computed(() => { const grouped = new Map() for (const permission of permissions.value) { const key = permission.groupLabel || 'Sonstiges' const current = grouped.get(key) if (current) current.push(permission) else grouped.set(key, [permission]) } return [...grouped.entries()].map(([label, items]) => ({ label, items, })) }) const selectedMember = computed(() => members.value.find((member) => member.id === editingMemberId.value) ?? null) const assignableRoleOptions = computed(() => roleOptions.value.filter((role) => role.value !== 'creator' || selectedMember.value?.role === 'creator', )) const hasRoleChanges = computed(() => Boolean(savedRoleSnapshot.value) && JSON.stringify(rolePermissionDrafts.value) !== savedRoleSnapshot.value, ) function resetMessages() { errorMessage.value = '' successMessage.value = '' } function applyTeamResponse(response: { members: AdminTeamMember[]; roles: AdminTeamRole[]; permissions: AdminTeamPermission[] }) { members.value = response.members roles.value = response.roles permissions.value = response.permissions rolePermissionDrafts.value = Object.fromEntries( response.roles.map((role) => [role.key, [...role.permissionKeys]]), ) savedRoleSnapshot.value = JSON.stringify(rolePermissionDrafts.value) } 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) { if (!silent) { errorMessage.value = error instanceof ApiRequestError ? error.message : 'Team-Daten konnten nicht geladen werden.' } } finally { if (showLoading) { loading.value = false } refreshingPresence.value = false } } function startCreateMember() { editingMemberId.value = null Object.assign(memberForm, emptyMemberForm()) generatedPassword.value = '' generatedPasswordLogin.value = '' resetMessages() } function startEditMember(member: AdminTeamMember) { editingMemberId.value = member.id memberForm.login = member.login memberForm.displayName = member.displayName memberForm.role = member.role memberForm.isActive = member.isActive generatedPassword.value = '' generatedPasswordLogin.value = '' resetMessages() } function validateMemberForm() { if (!memberForm.login.trim() && editingMemberId.value === null) { errorMessage.value = 'Bitte gib einen Login an.' return false } if (!memberForm.displayName.trim()) { errorMessage.value = 'Bitte gib einen Anzeigenamen an.' return false } return true } async function saveMember() { resetMessages() generatedPassword.value = '' generatedPasswordLogin.value = '' if (!validateMemberForm()) return false saving.value = true try { if (editingMemberId.value === null) { const result = await api.createAdminTeamMember({ login: memberForm.login, displayName: memberForm.displayName, role: memberForm.role, }) 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.' } else { await api.updateAdminTeamMember(editingMemberId.value, { login: memberForm.login, displayName: memberForm.displayName, role: memberForm.role, isActive: memberForm.isActive, }) await loadTeam({ silent: true }) successMessage.value = 'Team-Mitglied wurde gespeichert.' } return true } catch (error) { errorMessage.value = error instanceof ApiRequestError ? error.message : 'Team-Mitglied konnte nicht gespeichert werden.' return false } finally { saving.value = false } } async function resetMemberPassword(member: AdminTeamMember) { resetMessages() generatedPassword.value = '' generatedPasswordLogin.value = '' saving.value = true try { const result = await api.resetAdminTeamMemberPassword(member.id) 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.' } catch (error) { errorMessage.value = error instanceof ApiRequestError ? error.message : 'Passwort konnte nicht zurückgesetzt werden.' } finally { saving.value = false } } function requestDeleteMember(member: AdminTeamMember) { confirmDeleteMemberId.value = member.id resetMessages() } function cancelDeleteMember() { confirmDeleteMemberId.value = null } async function deleteMember(member: AdminTeamMember) { resetMessages() generatedPassword.value = '' generatedPasswordLogin.value = '' saving.value = true try { await api.deleteAdminTeamMember(member.id) confirmDeleteMemberId.value = null if (editingMemberId.value === member.id) { startCreateMember() } await loadTeam({ silent: true }) successMessage.value = 'Team-Mitglied wurde gelöscht.' } catch (error) { errorMessage.value = error instanceof ApiRequestError ? error.message : 'Team-Mitglied konnte nicht gelöscht werden.' } finally { saving.value = false } } function roleHasPermission(roleKey: string, permissionKey: string) { return rolePermissionDrafts.value[roleKey]?.includes(permissionKey) ?? false } function setRolePermission(roleKey: string, permissionKey: string, checked: boolean) { if (roleKey === 'owner') return const current = new Set(rolePermissionDrafts.value[roleKey] ?? []) if (checked) { current.add(permissionKey) } else { current.delete(permissionKey) } rolePermissionDrafts.value = { ...rolePermissionDrafts.value, [roleKey]: [...current].sort(), } } async function saveRolePermissions() { resetMessages() saving.value = true try { const result = await api.updateAdminTeamRoles({ roles: roles.value.map((role) => ({ key: role.key, permissionKeys: rolePermissionDrafts.value[role.key] ?? [], })), }) roles.value = result.roles rolePermissionDrafts.value = Object.fromEntries( result.roles.map((role) => [role.key, [...role.permissionKeys]]), ) savedRoleSnapshot.value = JSON.stringify(rolePermissionDrafts.value) successMessage.value = 'Rollen und Berechtigungen wurden gespeichert.' } catch (error) { errorMessage.value = error instanceof ApiRequestError ? error.message : 'Berechtigungen konnten nicht gespeichert werden.' } finally { saving.value = false } } let presenceRefreshTimer: ReturnType | 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, generatedPasswordLogin, confirmDeleteMemberId, members, roles, permissions, permissionGroups, memberForm, editingMemberId, selectedMember, activeMembers, pendingPasswordChanges, roleOptions, assignableRoleOptions, hasRoleChanges, loadTeam, startCreateMember, startEditMember, saveMember, resetMemberPassword, requestDeleteMember, cancelDeleteMember, deleteMember, roleHasPermission, setRolePermission, saveRolePermissions, } }