mandant-crm/frontend/pages/settings/accounts.vue

227 lines
6.4 KiB
Vue
Raw Normal View History

<script setup lang="ts">
import type { User } from '~/types'
definePageMeta({ middleware: ['auth', 'admin'] })
const { users, fetchUsers, createUser, updateUser, deleteUser } = useUsers()
await fetchUsers()
const editingId = ref<number | null>(null)
const form = ref<{
name: string
email: string
password: string
password_confirmation: string
role: 'admin' | 'staff'
}>({
name: '',
email: '',
password: '',
password_confirmation: '',
role: 'staff',
})
const error = ref('')
const resetForm = () => {
editingId.value = null
form.value = {
name: '',
email: '',
password: '',
password_confirmation: '',
role: 'staff',
}
error.value = ''
}
const startEdit = (user: User) => {
editingId.value = user.id
error.value = ''
form.value = {
name: user.name,
email: user.email,
password: '',
password_confirmation: '',
role: user.role,
}
}
const submit = async () => {
error.value = ''
if (!form.value.name.trim()) {
error.value = 'Bitte einen Namen angeben.'
return
}
if (!form.value.email.trim()) {
error.value = 'Bitte eine E-Mail angeben.'
return
}
try {
if (editingId.value) {
const payload: any = {
name: form.value.name.trim(),
email: form.value.email.trim(),
role: form.value.role,
}
if (form.value.password) {
payload.password = form.value.password
payload.password_confirmation = form.value.password_confirmation
}
await updateUser(editingId.value, payload)
} else {
if (!form.value.password) {
error.value = 'Bitte ein Passwort angeben.'
return
}
await createUser({
name: form.value.name.trim(),
email: form.value.email.trim(),
password: form.value.password,
password_confirmation: form.value.password_confirmation,
role: form.value.role,
})
}
resetForm()
} catch (e: any) {
error.value = e.data?.message || 'Fehler beim Speichern.'
}
}
const confirmDelete = (user: User) => {
if (confirm(`Benutzer "${user.name}" wirklich löschen?`)) {
deleteUser(user.id)
}
}
const roleLabels = {
admin: 'Admin',
staff: 'Mitarbeiter',
}
</script>
<template>
<div class="min-h-screen bg-gray-50">
<header class="bg-white border-b border-gray-200 px-6 py-3 flex items-center gap-4">
<NuxtLink
to="/clients"
title="Alle Mandanten"
aria-label="Alle Mandanten"
class="text-gray-500 hover:text-gray-700"
>
<IconArrowLeft />
</NuxtLink>
<h1 class="text-base font-semibold text-gray-800">Benutzer verwalten</h1>
</header>
<div class="max-w-3xl mx-auto py-6 px-6 space-y-6">
<!-- Existing users -->
<section class="bg-white border border-gray-200">
<table class="w-full text-sm">
<thead>
<tr class="border-b border-gray-200 text-left text-xs text-gray-500">
<th class="px-4 py-2 font-medium">Name</th>
<th class="px-4 py-2 font-medium">E-Mail</th>
<th class="px-4 py-2 font-medium">Rolle</th>
<th class="px-4 py-2 font-medium text-right">Aktionen</th>
</tr>
</thead>
<tbody>
<tr v-for="user in users" :key="user.id" class="border-b border-gray-100">
<td class="px-4 py-2 text-gray-800">{{ user.name }}</td>
<td class="px-4 py-2 text-gray-600">{{ user.email }}</td>
<td class="px-4 py-2 text-gray-600">{{ roleLabels[user.role] }}</td>
<td class="px-4 py-2 text-right space-x-2">
<button
@click="startEdit(user)"
title="Bearbeiten"
class="inline-flex items-center text-gray-400 hover:text-blue-600"
>
<IconEdit />
</button>
<button
@click="confirmDelete(user)"
title="Löschen"
class="inline-flex items-center text-gray-400 hover:text-red-600"
>
<IconTrash />
</button>
</td>
</tr>
</tbody>
</table>
</section>
<!-- Create/Edit form -->
<section class="bg-white border border-gray-200 p-6 space-y-4">
<h2 class="text-sm font-semibold text-gray-800">
{{ editingId ? 'Benutzer bearbeiten' : 'Neuer Benutzer' }}
</h2>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">Name</label>
<input
v-model="form.name"
type="text"
class="w-full border border-gray-300 px-3 py-2 text-sm"
/>
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">E-Mail</label>
<input
v-model="form.email"
type="email"
class="w-full border border-gray-300 px-3 py-2 text-sm"
/>
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">
{{ editingId ? 'Passwort (leer = nicht ändern)' : 'Passwort' }}
</label>
<input
v-model="form.password"
type="password"
class="w-full border border-gray-300 px-3 py-2 text-sm"
/>
</div>
<div v-if="form.password">
<label class="block text-xs font-medium text-gray-600 mb-1">Passwort wiederholen</label>
<input
v-model="form.password_confirmation"
type="password"
class="w-full border border-gray-300 px-3 py-2 text-sm"
/>
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">Rolle</label>
<select v-model="form.role" class="w-full border border-gray-300 px-3 py-2 text-sm">
<option value="staff">Mitarbeiter</option>
<option value="admin">Admin</option>
</select>
</div>
<p v-if="error" class="text-sm text-red-600">{{ error }}</p>
<div class="flex gap-2">
<button
@click="submit"
class="bg-blue-600 text-white px-4 py-1.5 text-sm hover:bg-blue-700"
>
{{ editingId ? 'Änderungen speichern' : 'Benutzer anlegen' }}
</button>
<button v-if="editingId" @click="resetForm" class="text-sm text-gray-500 hover:underline px-2">
Abbrechen
</button>
</div>
</section>
</div>
</div>
</template>