Files
BetiX/resources/js/pages/Admin/Chat.vue
Dolo 0280278978
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (8.4) (push) Has been cancelled
tests / ci (8.5) (push) Has been cancelled
Initialer Laravel Commit für BetiX
2026-04-04 18:01:50 +02:00

110 lines
4.7 KiB
Vue
Raw Permalink 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 { Head, router } from '@inertiajs/vue3';
import { onMounted, ref, nextTick } from 'vue';
import CasinoAdminLayout from '@/layouts/admin/CasinoAdminLayout.vue';
const props = defineProps<{ aiEnabled?: boolean }>();
const ai = ref(!!props.aiEnabled);
const toggling = ref(false);
async function toggleAi() {
toggling.value = true;
try {
await router.post('/admin/chat/toggle-ai', { enabled: ai.value }, { preserveScroll: true });
} finally {
toggling.value = false;
}
}
const messages = ref<any[]>([]);
const loading = ref(false);
async function loadMessages() {
loading.value = true;
try {
const res = await fetch('/api/chat?limit=50');
if (res.ok) {
const json = await res.json();
messages.value = json?.data || [];
}
} finally {
loading.value = false;
nextTick(() => { if ((window as any).lucide) (window as any).lucide.createIcons(); });
}
}
onMounted(() => {
loadMessages();
});
</script>
<template>
<CasinoAdminLayout>
<Head title="Admin Live Chat" />
<template #title>
Live Chat Management
</template>
<template #actions>
<label class="switch">
<input type="checkbox" v-model="ai" @change="toggleAi" :disabled="toggling" />
<span class="slider"></span>
<span class="ml-2 text-sm" :class="ai ? 'text-green' : 'text-muted'">AI {{ ai ? 'Enabled' : 'Disabled' }}</span>
</label>
</template>
<div class="panel">
<div class="panel-header">
<h3>Recent Messages</h3>
<button class="btn-ghost" @click="loadMessages" :disabled="loading">
<i data-lucide="refresh-ccw"></i> Refresh
</button>
</div>
<div class="chat-list">
<div v-for="m in messages" :key="m.id" class="chat-item">
<div class="avatar">{{ m.user?.username?.charAt(0)?.toUpperCase() || '?' }}</div>
<div class="content">
<div class="meta">
<span class="name">{{ m.user?.username || 'Unknown' }}</span>
<span class="time">{{ new Date(m.created_at).toLocaleString() }}</span>
</div>
<div class="text">{{ m.message }}</div>
</div>
<form :action="`/admin/chat/${m.id}`" method="post" class="actions" @submit.prevent="$el.submit()">
<input type="hidden" name="_method" value="DELETE" />
<button class="btn-danger" title="Delete message"><i data-lucide="trash-2"></i></button>
</form>
</div>
<div v-if="!messages.length && !loading" class="text-center py-8 text-muted">No messages yet.</div>
</div>
</div>
</CasinoAdminLayout>
</template>
<style scoped>
.panel { background: #111113; border: 1px solid #1f1f22; border-radius: 16px; }
.panel-header { display: flex; justify-content: space-between; align-items: center; padding: 16px 20px; border-bottom: 1px solid #1f1f22; }
.chat-list { display: flex; flex-direction: column; }
.chat-item { display: grid; grid-template-columns: 40px 1fr auto; gap: 12px; padding: 14px 20px; border-bottom: 1px solid #1f1f22; }
.avatar { width: 40px; height: 40px; border-radius: 50%; background: #27272a; color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 800; }
.meta { display: flex; gap: 8px; align-items: baseline; }
.meta .name { font-weight: 700; color: #fff; }
.meta .time { color: #a1a1aa; font-size: 12px; }
.text { color: #e4e4e7; }
.actions { display: flex; align-items: center; gap: 8px; }
.btn-ghost { background: transparent; border: none; color: #a1a1aa; display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.btn-ghost:hover { color: #fff; }
.btn-danger { background: transparent; border: 1px solid #7f1d1d; color: #ef4444; padding: 6px 10px; border-radius: 8px; cursor: pointer; }
.btn-danger:hover { background: rgba(239, 68, 68, .1); }
/* Switch */
.switch { display: inline-flex; align-items: center; }
.switch input { display: none; }
.switch .slider { width: 40px; height: 22px; background: #27272a; border-radius: 9999px; position: relative; transition: .2s; display: inline-block; }
.switch .slider:after { content: ''; width: 18px; height: 18px; background: #fff; border-radius: 50%; position: absolute; top: 2px; left: 2px; transition: .2s; }
.switch input:checked + .slider { background: #16a34a; }
.switch input:checked + .slider:after { transform: translateX(18px); }
.text-muted { color: #a1a1aa; }
.text-green { color: #16a34a; }
.text-white { color: #fff; }
</style>