100 lines
3.5 KiB
Vue
100 lines
3.5 KiB
Vue
|
|
<script setup lang="ts">
|
||
|
|
import type { Client } from '~/types'
|
||
|
|
|
||
|
|
definePageMeta({ middleware: 'auth' })
|
||
|
|
|
||
|
|
const route = useRoute()
|
||
|
|
const clientId = Number(route.params.id)
|
||
|
|
|
||
|
|
const { fetchClient, updateClient } = useClient()
|
||
|
|
const { entries, fetchEntries, addEntry, updateEntry, deleteEntry } = useHistory(clientId)
|
||
|
|
|
||
|
|
const client = ref<Client | null>(null)
|
||
|
|
client.value = await fetchClient(clientId)
|
||
|
|
await fetchEntries()
|
||
|
|
|
||
|
|
const editingName = ref(false)
|
||
|
|
const editName = ref(client.value?.name ?? '')
|
||
|
|
const editingFields = ref(false)
|
||
|
|
|
||
|
|
const saveName = async () => {
|
||
|
|
if (!client.value) return
|
||
|
|
client.value = await updateClient(clientId, { name: editName.value })
|
||
|
|
editingName.value = false
|
||
|
|
}
|
||
|
|
|
||
|
|
const saveFields = async (notes: Record<string, string>) => {
|
||
|
|
if (!client.value) return
|
||
|
|
client.value = await updateClient(clientId, { notes })
|
||
|
|
editingFields.value = false
|
||
|
|
}
|
||
|
|
|
||
|
|
const onAddEntry = async (payload: { type: string; body: string }) => {
|
||
|
|
await addEntry(payload)
|
||
|
|
}
|
||
|
|
|
||
|
|
const onUpdateEntry = async (id: number, body: string) => {
|
||
|
|
await updateEntry(id, body)
|
||
|
|
}
|
||
|
|
|
||
|
|
const onDeleteEntry = async (id: number) => {
|
||
|
|
if (!confirm('Eintrag wirklich löschen?')) return
|
||
|
|
await deleteEntry(id)
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<template>
|
||
|
|
<div v-if="client" 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" class="text-sm text-blue-600 hover:underline">← Alle Mandanten</NuxtLink>
|
||
|
|
<h1 class="text-base font-semibold text-gray-800">
|
||
|
|
<span class="font-mono text-gray-500">{{ client.client_number }}</span>
|
||
|
|
<span class="mx-2 text-gray-400">·</span>
|
||
|
|
<span v-if="!editingName">{{ client.name }}</span>
|
||
|
|
<span v-else class="inline-flex gap-2 items-center">
|
||
|
|
<input v-model="editName" class="border border-gray-300 px-2 py-0.5 text-sm" />
|
||
|
|
<button @click="saveName" class="text-sm bg-blue-600 text-white px-2 py-0.5 hover:bg-blue-700">OK</button>
|
||
|
|
<button @click="editingName = false" class="text-sm text-gray-500">Abbrechen</button>
|
||
|
|
</span>
|
||
|
|
</h1>
|
||
|
|
<button v-if="!editingName" @click="editingName = true" class="text-xs text-gray-400 hover:text-gray-600">
|
||
|
|
Name ändern
|
||
|
|
</button>
|
||
|
|
<NuxtLink :to="`/clients/${clientId}/print`" class="ml-auto text-sm text-gray-500 hover:underline">
|
||
|
|
Drucken
|
||
|
|
</NuxtLink>
|
||
|
|
</header>
|
||
|
|
|
||
|
|
<div class="max-w-4xl mx-auto py-6 px-6 space-y-6">
|
||
|
|
<!-- Configurable fields -->
|
||
|
|
<section class="bg-white border border-gray-200 p-4">
|
||
|
|
<div class="flex items-center justify-between mb-3">
|
||
|
|
<h2 class="text-sm font-semibold text-gray-700">Stammdaten</h2>
|
||
|
|
<button @click="editingFields = !editingFields" class="text-xs text-blue-600 hover:underline">
|
||
|
|
{{ editingFields ? 'Abbrechen' : 'Bearbeiten' }}
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
<ClientFields :client="client" :editing="editingFields" @save="saveFields" />
|
||
|
|
</section>
|
||
|
|
|
||
|
|
<!-- History -->
|
||
|
|
<section>
|
||
|
|
<h2 class="text-sm font-semibold text-gray-700 mb-3">Verlauf</h2>
|
||
|
|
<HistoryForm @submit="onAddEntry" />
|
||
|
|
<div class="mt-3 space-y-2">
|
||
|
|
<HistoryEntry
|
||
|
|
v-for="entry in entries"
|
||
|
|
:key="entry.id"
|
||
|
|
:entry="entry"
|
||
|
|
@update="onUpdateEntry"
|
||
|
|
@delete="onDeleteEntry"
|
||
|
|
/>
|
||
|
|
<p v-if="entries.length === 0" class="text-sm text-gray-400 italic py-4 text-center">
|
||
|
|
Noch keine Einträge.
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</template>
|