491 lines
33 KiB
PHP
491 lines
33 KiB
PHP
@extends('layouts.dashboard')
|
|
|
|
@section('title', 'Sistem Pengumuman Digital')
|
|
|
|
@section('content')
|
|
<div class="min-h-screen bg-gray-50">
|
|
<!-- Header -->
|
|
<div class="bg-white shadow-sm">
|
|
<div class="container mx-auto px-4 py-6">
|
|
<div class="flex flex-col md:flex-row justify-between items-start md:items-center">
|
|
<div>
|
|
<h1 class="text-2xl font-bold text-gray-800">Sistem Pengumuman Digital</h1>
|
|
<p class="text-gray-600 mt-1">Kontrol Terpusat untuk Ruangan dan Pengumuman</p>
|
|
</div>
|
|
<div class="mt-4 md:mt-0 flex items-center space-x-4">
|
|
<div class="flex items-center bg-white px-4 py-2 rounded-full shadow-sm border border-gray-200">
|
|
<div class="w-3 h-3 rounded-full mr-2 {{ $mqttStatus === 'Connected' ? 'bg-green-500' : 'bg-red-500' }}"></div>
|
|
<span class="text-sm font-medium">MQTT: {{ $mqttStatus }}</span>
|
|
</div>
|
|
<button onclick="window.location.reload()" class="p-2 text-gray-500 hover:text-blue-600 transition-colors">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M4 2a1 1 0 011 1v2.101a7.002 7.002 0 0111.601 2.566 1 1 0 11-1.885.666A5.002 5.002 0 005.999 7H9a1 1 0 010 2H4a1 1 0 01-1-1V3a1 1 0 011-1zm.008 9.057a1 1 0 011.276.61A5.002 5.002 0 0014.001 13H11a1 1 0 110-2h5a1 1 0 011 1v5a1 1 0 11-2 0v-2.101a7.002 7.002 0 01-11.601-2.566 1 1 0 01.61-1.276z" clip-rule="evenodd" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Main Content -->
|
|
<div class="container mx-auto px-4 py-8">
|
|
<!-- Mode Selection Card -->
|
|
<div class="bg-white rounded-xl shadow-md overflow-hidden mb-8">
|
|
<div class="border-b border-gray-200">
|
|
<nav class="flex -mb-px">
|
|
<button id="reguler-tab" class="tab-button active" data-tab="reguler">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M11.3 1.046A1 1 0 0112 2v5h4a1 1 0 01.82 1.573l-7 10A1 1 0 018 18v-5H4a1 1 0 01-.82-1.573l7-10a1 1 0 011.12-.38z" clip-rule="evenodd" />
|
|
</svg>
|
|
Kontrol Relay
|
|
</button>
|
|
<button id="tts-tab" class="tab-button" data-tab="tts">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M9.383 3.076A1 1 0 0110 4v12a1 1 0 01-1.707.707L4.586 13H2a1 1 0 01-1-1V8a1 1 0 011-1h2.586l3.707-3.707a1 1 0 011.09-.217zM14.657 2.929a1 1 0 011.414 0A9.972 9.972 0 0119 10a9.972 9.972 0 01-2.929 7.071 1 1 0 01-1.414-1.414A7.971 7.971 0 0017 10c0-2.21-.894-4.208-2.343-5.657a1 1 0 010-1.414zm-2.829 2.828a1 1 0 011.415 0A5.983 5.983 0 0115 10a5.984 5.984 0 01-1.757 4.243 1 1 0 01-1.415-1.415A3.984 3.984 0 0013 10a3.983 3.983 0 00-1.172-2.828 1 1 0 010-1.415z" clip-rule="evenodd" />
|
|
</svg>
|
|
Pengumuman Suara
|
|
</button>
|
|
</nav>
|
|
</div>
|
|
|
|
<div class="p-6">
|
|
<!-- Reguler Tab Content -->
|
|
<div id="reguler-content" class="tab-content active">
|
|
<form id="reguler-form" action="{{ route('announcement.store') }}" method="POST">
|
|
@csrf
|
|
<input type="hidden" name="mode" value="reguler">
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
|
<!-- Ruangan Selection -->
|
|
<div class="lg:col-span-2">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h2 class="text-lg font-semibold text-gray-800">Pilih Ruangan</h2>
|
|
<button type="button" id="selectAllBtn" class="text-sm text-blue-600 hover:text-blue-800 font-medium">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 inline mr-1" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
|
|
</svg>
|
|
Pilih Semua
|
|
</button>
|
|
</div>
|
|
|
|
<div class="bg-gray-50 p-4 rounded-lg border border-gray-200">
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 max-h-96 overflow-y-auto p-2">
|
|
@foreach($ruangans as $ruangan)
|
|
<div class="flex items-center p-3 hover:bg-gray-100 rounded-lg transition">
|
|
<input id="ruangan-{{ $ruangan->id }}" name="ruangans[]" type="checkbox"
|
|
value="{{ $ruangan->id }}"
|
|
class="room-checkbox h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
|
|
<label for="ruangan-{{ $ruangan->id }}" class="ml-3 flex-1">
|
|
<div class="flex justify-between items-center">
|
|
<span class="block text-gray-800 font-medium">{{ $ruangan->nama_ruangan }}</span>
|
|
<span class="relay-status text-xs px-2 py-1 rounded-full
|
|
{{ $ruangan->relay_state === 'ON' ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800' }}">
|
|
{{ $ruangan->relay_state ?? 'OFF' }}
|
|
</span>
|
|
</div>
|
|
<span class="block text-xs text-gray-500 mt-1">
|
|
{{ $ruangan->kelas->nama_kelas ?? '-' }} •
|
|
{{ $ruangan->jurusan->nama_jurusan ?? '-' }}
|
|
</span>
|
|
</label>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
@error('ruangans')
|
|
<p class="mt-2 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Relay Control Panel -->
|
|
<div>
|
|
<h2 class="text-lg font-semibold text-gray-800 mb-4">Kontrol Relay</h2>
|
|
<div class="bg-white p-5 rounded-lg border border-gray-200 shadow-sm">
|
|
<div class="space-y-4">
|
|
<div class="flex items-center p-3 rounded-lg bg-blue-50 border border-blue-100">
|
|
<input id="relay-on" name="relay_action" type="radio" value="ON" checked
|
|
class="h-4 w-4 text-blue-600 focus:ring-blue-500">
|
|
<label for="relay-on" class="ml-3 flex items-center">
|
|
<span class="w-3 h-3 rounded-full bg-green-500 mr-3"></span>
|
|
<span class="text-gray-700 font-medium">Aktifkan Relay</span>
|
|
</label>
|
|
</div>
|
|
<div class="flex items-center p-3 rounded-lg bg-red-50 border border-red-100">
|
|
<input id="relay-off" name="relay_action" type="radio" value="OFF"
|
|
class="h-4 w-4 text-blue-600 focus:ring-blue-500">
|
|
<label for="relay-off" class="ml-3 flex items-center">
|
|
<span class="w-3 h-3 rounded-full bg-red-500 mr-3"></span>
|
|
<span class="text-gray-700 font-medium">Nonaktifkan Relay</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-6 pt-5 border-t border-gray-200">
|
|
<button type="submit"
|
|
class="w-full flex justify-center items-center px-4 py-3 bg-gradient-to-r from-blue-600 to-blue-700 text-white font-medium rounded-lg hover:from-blue-700 hover:to-blue-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-all shadow-md">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
|
|
<path d="M10.894 2.553a1 1 0 00-1.788 0l-7 14a1 1 0 001.169 1.409l5-1.429A1 1 0 009 15.571V11a1 1 0 112 0v4.571a1 1 0 00.725.962l5 1.428a1 1 0 001.17-1.408l-7-14z" />
|
|
</svg>
|
|
Eksekusi Perintah
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- TTS Tab Content -->
|
|
<div id="tts-content" class="tab-content hidden">
|
|
<form id="tts-form" action="{{ route('announcement.store') }}" method="POST">
|
|
@csrf
|
|
<input type="hidden" name="mode" value="tts">
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
|
<div class="lg:col-span-2">
|
|
<h2 class="text-lg font-semibold text-gray-800 mb-4">Buat Pengumuman Suara</h2>
|
|
|
|
<!-- TTS Editor -->
|
|
<div class="mb-6">
|
|
<label for="tts_text" class="block text-gray-700 font-medium mb-2">Teks Pengumuman</label>
|
|
<div class="relative">
|
|
<textarea id="tts_text" name="tts_text" rows="6"
|
|
class="w-full px-4 py-3 text-gray-700 border border-gray-300 rounded-lg focus:ring-blue-500 focus:border-blue-500 shadow-sm"
|
|
placeholder="Ketikkan teks pengumuman di sini..."></textarea>
|
|
<div class="absolute bottom-3 right-3 text-xs text-gray-400" id="charCount">0/1000 karakter</div>
|
|
</div>
|
|
@error('tts_text')
|
|
<p class="mt-2 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
|
|
<!-- Voice Settings -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
|
|
<div>
|
|
<label for="tts_voice" class="block text-gray-700 font-medium mb-2">Jenis Suara</label>
|
|
<div class="relative">
|
|
<select id="tts_voice" name="tts_voice"
|
|
class="block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 rounded-lg shadow-sm">
|
|
<option value="id-id">Bahasa Indonesia</option>
|
|
<option value="en-us">English (US)</option>
|
|
<option value="en-gb">English (UK)</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label for="tts_speed" class="block text-gray-700 font-medium mb-2">Kecepatan Bicara</label>
|
|
<div class="px-2">
|
|
<input type="range" id="tts_speed" name="tts_speed" min="-10" max="10" value="0"
|
|
class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
|
|
<div class="flex justify-between text-xs text-gray-500 mt-1 px-1">
|
|
<span>Lambat</span>
|
|
<span>Normal</span>
|
|
<span>Cepat</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Preview Section -->
|
|
<div class="bg-gray-50 p-4 rounded-lg border border-gray-200">
|
|
<div class="flex justify-between items-center mb-3">
|
|
<h3 class="text-sm font-medium text-gray-700">Preview Suara</h3>
|
|
<button type="button" id="previewBtn"
|
|
class="inline-flex items-center px-3 py-1.5 border border-gray-300 shadow-sm text-xs font-medium rounded-lg text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z" clip-rule="evenodd" />
|
|
</svg>
|
|
Generate Preview
|
|
</button>
|
|
</div>
|
|
<div id="previewContainer" class="hidden">
|
|
<audio id="previewAudio" controls class="w-full mt-2"></audio>
|
|
<div id="previewLoading" class="mt-3 text-center py-4 hidden">
|
|
<svg class="animate-spin mx-auto h-5 w-5 text-blue-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
</svg>
|
|
<p class="mt-2 text-sm text-gray-500">Sedang memproses suara...</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Ruangan Selection -->
|
|
<div>
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h2 class="text-lg font-semibold text-gray-800">Ruangan Tujuan</h2>
|
|
<button type="button" id="selectAllTtsBtn" class="text-sm text-blue-600 hover:text-blue-800 font-medium">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 inline mr-1" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
|
|
</svg>
|
|
Pilih Semua
|
|
</button>
|
|
</div>
|
|
<div class="bg-gray-50 p-4 rounded-lg border border-gray-200 max-h-96 overflow-y-auto">
|
|
@foreach($ruangans as $ruangan)
|
|
<div class="flex items-start mb-3">
|
|
<div class="flex items-center h-5 mt-1">
|
|
<input id="tts-ruangan-{{ $ruangan->id }}" name="ruangans[]" type="checkbox"
|
|
value="{{ $ruangan->id }}"
|
|
class="tts-room-checkbox h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
|
|
</div>
|
|
<label for="tts-ruangan-{{ $ruangan->id }}" class="ml-3">
|
|
<span class="block text-gray-800 font-medium">{{ $ruangan->nama_ruangan }}</span>
|
|
<span class="block text-xs text-gray-500">
|
|
{{ $ruangan->kelas->nama_kelas ?? '-' }} •
|
|
{{ $ruangan->jurusan->nama_jurusan ?? '-' }}
|
|
</span>
|
|
</label>
|
|
</div>
|
|
@endforeach
|
|
@error('ruangans')
|
|
<p class="mt-2 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
|
|
<div class="mt-6 pt-5 border-t border-gray-200">
|
|
<button type="submit"
|
|
class="w-full flex justify-center items-center px-4 py-3 bg-gradient-to-r from-purple-600 to-purple-700 text-white font-medium rounded-lg hover:from-purple-700 hover:to-purple-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-500 transition-all shadow-md">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
|
|
<path d="M10.894 2.553a1 1 0 00-1.788 0l-7 14a1 1 0 001.169 1.409l5-1.429A1 1 0 009 15.571V11a1 1 0 112 0v4.571a1 1 0 00.725.962l5 1.428a1 1 0 001.17-1.408l-7-14z" />
|
|
</svg>
|
|
Kirim Pengumuman
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Announcements -->
|
|
<div class="mt-8 bg-white rounded-xl shadow-md overflow-hidden">
|
|
<div class="px-6 py-4 border-b border-gray-200 bg-gray-50">
|
|
<h2 class="text-lg font-semibold text-gray-800">Riwayat Pengumuman Terakhir</h2>
|
|
</div>
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full divide-y divide-gray-200">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Waktu</th>
|
|
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Mode</th>
|
|
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Konten</th>
|
|
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="bg-white divide-y divide-gray-200">
|
|
@forelse($announcements as $announcement)
|
|
<tr class="hover:bg-gray-50 transition-colors">
|
|
<td class="px-6 py-4 whitespace-nowrap">
|
|
<div class="text-sm font-medium text-gray-900">{{ $announcement->sent_at->format('d M Y') }}</div>
|
|
<div class="text-sm text-gray-500">{{ $announcement->sent_at->format('H:i') }}</div>
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap">
|
|
<span class="px-2.5 py-0.5 inline-flex items-center text-xs font-medium rounded-full
|
|
{{ $announcement->mode === 'reguler' ? 'bg-blue-100 text-blue-800' : 'bg-purple-100 text-purple-800' }}">
|
|
{{ $announcement->mode === 'reguler' ? 'Kontrol Relay' : 'Pengumuman Suara' }}
|
|
</span>
|
|
</td>
|
|
<td class="px-6 py-4">
|
|
<div class="text-sm font-medium text-gray-900">
|
|
@if($announcement->mode === 'reguler')
|
|
{{ $announcement->message }}
|
|
<span class="text-xs font-normal ml-2 {{ $announcement->relay_state === 'ON' ? 'text-green-600' : 'text-red-600' }}">
|
|
(Relay: {{ $announcement->relay_state }})
|
|
</span>
|
|
@else
|
|
{{ Str::limit($announcement->message, 50) }}
|
|
@endif
|
|
</div>
|
|
<div class="text-xs text-gray-500 mt-1">
|
|
Ruangan: {{ $announcement->ruangans->pluck('nama_ruangan')->implode(', ') }}
|
|
</div>
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap">
|
|
<div class="flex items-center">
|
|
<span class="px-2.5 py-0.5 inline-flex text-xs font-medium rounded-full
|
|
{{ $announcement->status === 'delivered' ? 'bg-green-100 text-green-800' : ($announcement->status === 'failed' ? 'bg-red-100 text-red-800' : 'bg-yellow-100 text-yellow-800') }}">
|
|
{{ ucfirst($announcement->status) }}
|
|
</span>
|
|
@if($announcement->error_message)
|
|
<button onclick="showErrorModal('{{ $announcement->error_message }}')" class="ml-2 text-gray-400 hover:text-gray-500">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd" />
|
|
</svg>
|
|
</button>
|
|
@endif
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
@empty
|
|
<tr>
|
|
<td colspan="4" class="px-6 py-4 text-center text-sm text-gray-500">
|
|
Belum ada riwayat pengumuman
|
|
</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="px-6 py-4 border-t border-gray-200 bg-gray-50">
|
|
{{ $announcements->links() }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Error Modal -->
|
|
<div id="errorModal" class="fixed inset-0 z-50 hidden overflow-y-auto">
|
|
<div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
|
|
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
|
|
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
|
|
</div>
|
|
<div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
|
|
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
|
|
<div class="sm:flex sm:items-start">
|
|
<div class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-red-600" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" />
|
|
</svg>
|
|
</div>
|
|
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
|
<h3 class="text-lg leading-6 font-medium text-gray-900">Error Details</h3>
|
|
<div class="mt-2">
|
|
<p id="errorModalContent" class="text-sm text-gray-500"></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
|
|
<button type="button" onclick="closeErrorModal()" class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm">
|
|
Tutup
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- JavaScript -->
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Tab Switching
|
|
const tabs = document.querySelectorAll('.tab-button');
|
|
tabs.forEach(tab => {
|
|
tab.addEventListener('click', () => {
|
|
// Update tab buttons
|
|
tabs.forEach(t => t.classList.remove('active', 'border-blue-500', 'text-blue-600'));
|
|
tab.classList.add('active', 'border-blue-500', 'text-blue-600');
|
|
|
|
// Update tab contents
|
|
const tabId = tab.getAttribute('data-tab');
|
|
document.querySelectorAll('.tab-content').forEach(content => {
|
|
content.classList.add('hidden');
|
|
content.classList.remove('active');
|
|
});
|
|
document.getElementById(`${tabId}-content`).classList.remove('hidden');
|
|
document.getElementById(`${tabId}-content`).classList.add('active');
|
|
});
|
|
});
|
|
|
|
// Select All Rooms - Reguler
|
|
document.getElementById('selectAllBtn').addEventListener('click', function() {
|
|
const checkboxes = document.querySelectorAll('.room-checkbox');
|
|
const allChecked = Array.from(checkboxes).every(checkbox => checkbox.checked);
|
|
|
|
checkboxes.forEach(checkbox => {
|
|
checkbox.checked = !allChecked;
|
|
});
|
|
|
|
this.innerHTML = allChecked ?
|
|
'<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 inline mr-1" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" /></svg>Pilih Semua' :
|
|
'<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 inline mr-1" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" /></svg>Batal Pilih';
|
|
});
|
|
|
|
// Select All Rooms - TTS
|
|
document.getElementById('selectAllTtsBtn').addEventListener('click', function() {
|
|
const checkboxes = document.querySelectorAll('.tts-room-checkbox');
|
|
const allChecked = Array.from(checkboxes).every(checkbox => checkbox.checked);
|
|
|
|
checkboxes.forEach(checkbox => {
|
|
checkbox.checked = !allChecked;
|
|
});
|
|
|
|
this.innerHTML = allChecked ?
|
|
'<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 inline mr-1" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" /></svg>Pilih Semua' :
|
|
'<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 inline mr-1" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" /></svg>Batal Pilih';
|
|
});
|
|
|
|
// Character Count for TTS
|
|
document.getElementById('tts_text').addEventListener('input', function() {
|
|
const count = this.value.length;
|
|
document.getElementById('charCount').textContent = `${count}/1000 karakter`;
|
|
});
|
|
|
|
// TTS Preview
|
|
document.getElementById('previewBtn').addEventListener('click', function() {
|
|
const text = document.getElementById('tts_text').value;
|
|
const voice = document.getElementById('tts_voice').value;
|
|
const speed = document.getElementById('tts_speed').value;
|
|
const previewContainer = document.getElementById('previewContainer');
|
|
const previewAudio = document.getElementById('previewAudio');
|
|
const previewLoading = document.getElementById('previewLoading');
|
|
|
|
if (!text) {
|
|
alert('Masukkan teks terlebih dahulu');
|
|
return;
|
|
}
|
|
|
|
// Show loading
|
|
previewContainer.classList.remove('hidden');
|
|
previewAudio.classList.add('hidden');
|
|
previewLoading.classList.remove('hidden');
|
|
|
|
fetch("{{ route('announcement.tts-preview') }}", {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
|
},
|
|
body: JSON.stringify({
|
|
text: text,
|
|
voice: voice,
|
|
speed: speed
|
|
})
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.error) {
|
|
alert(data.error);
|
|
previewContainer.classList.add('hidden');
|
|
} else {
|
|
previewAudio.src = data.audio_url;
|
|
previewLoading.classList.add('hidden');
|
|
previewAudio.classList.remove('hidden');
|
|
previewAudio.play();
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
alert('Gagal membuat preview suara');
|
|
previewContainer.classList.add('hidden');
|
|
});
|
|
});
|
|
|
|
// Initialize first tab
|
|
document.querySelector('.tab-button').click();
|
|
});
|
|
|
|
// Error Modal Functions
|
|
function showErrorModal(message) {
|
|
document.getElementById('errorModalContent').textContent = message;
|
|
document.getElementById('errorModal').classList.remove('hidden');
|
|
}
|
|
|
|
function closeErrorModal() {
|
|
document.getElementById('errorModal').classList.add('hidden');
|
|
}
|
|
</script>
|
|
|
|
@endsection |