Initialer Laravel Commit für BetiX
This commit is contained in:
110
resources/js/pages/Admin/Chat.vue
Normal file
110
resources/js/pages/Admin/Chat.vue
Normal file
@@ -0,0 +1,110 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user