mandant-crm/frontend/components/history/HistoryEntry.vue
Tim Stollberg 570f17e8b8 feat(frontend): commit uncommitted settings, custom fields, and import work
This local working tree had accumulated a substantial amount of
finished-but-never-committed frontend work: custom client fields
(replacing the old static ClientFields with a dynamic
ClientCustomFieldCard + useCustomFields), CSV import
(useImport + settings/import page), history type management
(useHistoryTypes + settings/history-types page), an admin-only route
middleware, several new icon components, a shared useApiFetch
composable, and a client detail page restructure ([id].vue ->
[id]/index.vue). None of it had ever been pushed, so production was
running a stale build that was already linking to routes/components
that didn't exist server-side (missing IconSettings, 404s on
/settings/import, etc). This commit brings the repo in line with
local state.
2026-07-18 16:27:19 +07:00

90 lines
3.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import type { HistoryEntry } from '~/types'
const props = defineProps<{ entry: HistoryEntry }>()
const emit = defineEmits<{
delete: [id: number]
update: [id: number, payload: { body: string; occurred_at: string | null }]
}>()
const { user } = useAuth()
// Auto-generated change entries are read-only audit records; only the author
// may edit their own manual notes.
const canEdit = computed(() => !props.entry.is_field_change && props.entry.author_id === user.value?.id)
// Only admins may delete Verlauf entries (manual notes and change entries alike).
const canDelete = computed(() => user.value?.role === 'admin')
const editing = ref(false)
const editBody = ref(props.entry.body)
// datetime-local wants "YYYY-MM-DDTHH:MM" (no seconds); occurred_at carries seconds.
const editOccurredAt = ref(props.entry.occurred_at?.slice(0, 16) ?? '')
const saveEdit = () => {
const occurred_at = props.entry.requires_datetime && editOccurredAt.value
? `${editOccurredAt.value}:00`
: null
emit('update', props.entry.id, { body: editBody.value, occurred_at })
editing.value = false
}
const formatDate = (iso: string) =>
new Date(iso).toLocaleString('de-DE', { dateStyle: 'short', timeStyle: 'short' })
</script>
<template>
<div class="border border-gray-200 bg-white p-4">
<div class="flex items-start justify-between gap-2 mb-2">
<div class="flex items-center gap-2">
<span class="text-xs font-medium bg-gray-100 text-gray-600 px-2 py-0.5">
{{ entry.type_name ?? '—' }}<template v-if="entry.occurred_at"> {{ formatEventDateTime(entry.occurred_at) }}</template>
</span>
<span class="text-xs text-gray-400">{{ formatDate(entry.created_at) }}</span>
<span class="text-xs text-gray-400">{{ entry.author_name }}</span>
<span v-if="entry.updated_by_name" class="text-xs text-gray-400 italic">
(bearb. {{ entry.updated_by_name }})
</span>
</div>
<div class="flex gap-1 shrink-0">
<button
v-if="canEdit"
@click="editing = !editing"
:title="editing ? 'Abbrechen' : 'Bearbeiten'"
:aria-label="editing ? 'Abbrechen' : 'Bearbeiten'"
class="p-1 text-gray-400 hover:text-blue-600"
>
<IconClose v-if="editing" />
<IconEdit v-else />
</button>
<button
v-if="canDelete"
@click="emit('delete', entry.id)"
title="Löschen"
aria-label="Löschen"
class="p-1 text-gray-400 hover:text-red-600"
>
<IconTrash />
</button>
</div>
</div>
<div v-if="!editing" class="text-sm text-gray-800 whitespace-pre-wrap">{{ entry.body }}</div>
<div v-else class="space-y-2">
<div v-if="entry.requires_datetime">
<label class="block text-xs font-medium text-gray-600 mb-1">Datum/Uhrzeit</label>
<input
v-model="editOccurredAt"
type="datetime-local"
class="border border-gray-300 px-2 py-1.5 text-sm"
/>
</div>
<textarea
v-model="editBody"
rows="4"
class="w-full border border-gray-300 px-3 py-2 text-sm resize-y"
/>
<button @click="saveEdit" class="bg-blue-600 text-white px-3 py-1 text-sm hover:bg-blue-700">
Speichern
</button>
</div>
</div>
</template>