pp-planer/resources/js/Pages/Settings/LabelImport.vue

139 lines
5.5 KiB
Vue

<script setup>
import { computed, ref } from 'vue'
import { route } from 'ziggy-js'
const props = defineProps({
labels: { type: Array, default: () => [] },
last_labels_import: { type: Object, default: () => ({}) },
})
const uploading = ref(false)
const result = ref(null)
const error = ref(null)
const sortedLabels = computed(() => [...props.labels].sort((a, b) => a.name.localeCompare(b.name)))
async function handleFileChange(event) {
const file = event.target.files[0]
if (!file) return
uploading.value = true
error.value = null
result.value = null
const form = new FormData()
form.append('file', file)
try {
const res = await fetch(route('settings.labels.import'), {
method: 'POST',
headers: {
'X-Requested-With': 'XMLHttpRequest',
'X-XSRF-TOKEN': decodeURIComponent(document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1] ?? ''),
},
body: form,
})
if (!res.ok) {
const data = await res.json()
error.value = data.message || 'Import fehlgeschlagen'
return
}
result.value = await res.json()
event.target.value = ''
window.location.reload()
} catch {
error.value = 'Netzwerkfehler beim Upload'
} finally {
uploading.value = false
}
}
</script>
<template>
<div>
<h3 class="mb-1 text-sm font-semibold text-gray-900">Label-Import</h3>
<p class="mb-1 text-xs text-gray-500">
Diese Datei findest du im ProPresenter-Ordner unter <strong>Configuration</strong>.
<span class="group relative inline-block">
<svg
class="ml-1 inline h-3.5 w-3.5 cursor-help text-gray-400"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2"
>
<path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span class="absolute bottom-full left-0 z-10 mb-2 hidden w-72 rounded-lg border border-gray-200 bg-white p-3 text-xs text-gray-600 shadow-lg group-hover:block">
<strong>macOS:</strong> ~/Library/Application Support/RenewedVision/ProPresenter/Configuration/Labels<br><br>
<strong>Windows:</strong> %APPDATA%\RenewedVision\ProPresenter\Configuration\Labels
</span>
</span>
</p>
<div v-if="last_labels_import?.at" class="mb-4 text-xs text-gray-400">
Letzter Import: {{ last_labels_import.at }}
<span v-if="last_labels_import.filename">({{ last_labels_import.filename }})</span>
</div>
<label
class="mb-4 flex cursor-pointer flex-col items-center justify-center rounded-xl border-2 border-dashed border-gray-200 bg-gray-50 p-6 transition-colors hover:border-amber-300 hover:bg-amber-50"
data-testid="labels-upload-area"
>
<svg class="mb-2 h-8 w-8 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5" />
</svg>
<span class="text-sm text-gray-500">
{{ uploading ? 'Wird importiert...' : 'Labels-Datei auswählen oder hierher ziehen' }}
</span>
<input
type="file"
class="hidden"
:disabled="uploading"
data-testid="labels-file-input"
@change="handleFileChange"
/>
</label>
<div
v-if="error"
class="mb-4 rounded-lg bg-red-50 p-3 text-sm text-red-700"
data-testid="labels-import-error"
>
{{ error }}
</div>
<div
v-if="result"
class="mb-4 rounded-lg bg-green-50 p-3 text-sm text-green-700"
data-testid="labels-import-summary"
>
<strong>Import abgeschlossen:</strong>
{{ result.new }} neue Labels importiert, {{ result.updated }} bestehende Labels aktualisiert.
Insgesamt {{ result.total }} Labels in Datei.
</div>
<div v-if="sortedLabels.length > 0">
<h4 class="mb-2 text-xs font-semibold uppercase tracking-wide text-gray-500">
Label-Bibliothek ({{ sortedLabels.length }})
</h4>
<div class="divide-y divide-gray-100 rounded-lg border border-gray-100">
<div
v-for="label in sortedLabels"
:key="label.id"
class="flex items-center gap-3 px-3 py-2 text-sm"
:data-testid="'labels-registry-row-' + label.name"
>
<span
class="h-4 w-4 shrink-0 rounded border border-gray-200"
:style="label.color ? { backgroundColor: label.color } : { backgroundColor: '#e5e7eb' }"
/>
<span class="flex-1 text-gray-700">{{ label.name }}</span>
<span v-if="label.color" class="font-mono text-xs text-gray-400">{{ label.color }}</span>
</div>
</div>
</div>
<p v-else class="text-sm text-gray-400">Noch keine Labels importiert.</p>
</div>
</template>