692 lines
34 KiB
PHP
692 lines
34 KiB
PHP
@extends('layouts.dashboard')
|
|
|
|
@section('title', 'Manajemen Pengumuman')
|
|
|
|
@section('content')
|
|
<div class="container mx-auto px-4 py-8">
|
|
<!-- Header Section -->
|
|
<div class="flex flex-col md:flex-row justify-between items-start md:items-center mb-8">
|
|
<div>
|
|
<h1 class="text-3xl font-bold text-gray-800">Sistem Pengumuman Digital</h1>
|
|
<p class="text-gray-600 mt-2">Kelola dan kirim pengumuman ke ruangan terpilih</p>
|
|
</div>
|
|
<div class="mt-4 md:mt-0 flex space-x-3">
|
|
<a href="{{ route('announcement.history') }}"
|
|
class="flex items-center px-5 py-2.5 bg-indigo-50 text-indigo-700 rounded-lg hover:bg-indigo-100 transition duration-300 shadow-sm">
|
|
<i class="fas fa-history mr-2"></i> Riwayat
|
|
</a>
|
|
<button id="help-btn" class="flex items-center px-5 py-2.5 bg-gray-50 text-gray-700 rounded-lg hover:bg-gray-100 transition duration-300 shadow-sm">
|
|
<i class="fas fa-question-circle mr-2"></i> Bantuan
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Main Card -->
|
|
<div class="bg-white rounded-xl shadow-lg overflow-hidden mb-8 border border-gray-100">
|
|
<!-- Card Header -->
|
|
<div class="bg-gradient-to-r from-blue-600 to-indigo-700 px-6 py-4">
|
|
<h2 class="text-xl font-semibold text-white">Formulir Pengumuman Baru</h2>
|
|
</div>
|
|
|
|
<!-- Card Body -->
|
|
<div class="p-6">
|
|
<form id="announcementForm" action="{{ route('announcement.store') }}" method="POST">
|
|
@csrf
|
|
|
|
<!-- Mode Selection -->
|
|
<div class="mb-8">
|
|
<label class="block text-gray-700 font-medium mb-3">Jenis Pengumuman</label>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<label class="mode-option">
|
|
<input type="radio" name="mode" value="reguler" checked
|
|
class="absolute opacity-0 h-0 w-0 mode-selector" data-mode="reguler">
|
|
<div class="border-2 border-gray-200 rounded-xl p-5 flex items-center hover:border-blue-400 transition duration-200 cursor-pointer h-full">
|
|
<div class="mr-4">
|
|
<div class="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center">
|
|
<i class="fas fa-align-left text-blue-600 text-lg"></i>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<h3 class="font-medium text-gray-800">Pengumuman Teks</h3>
|
|
<p class="text-sm text-gray-500 mt-1">Kirim pengumuman berupa teks biasa</p>
|
|
</div>
|
|
</div>
|
|
</label>
|
|
<label class="mode-option">
|
|
<input type="radio" name="mode" value="tts"
|
|
class="absolute opacity-0 h-0 w-0 mode-selector" data-mode="tts">
|
|
<div class="border-2 border-gray-200 rounded-xl p-5 flex items-center hover:border-purple-400 transition duration-200 cursor-pointer h-full">
|
|
<div class="mr-4">
|
|
<div class="w-10 h-10 rounded-full bg-purple-100 flex items-center justify-center">
|
|
<i class="fas fa-volume-up text-purple-600 text-lg"></i>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<h3 class="font-medium text-gray-800">Pengumuman Suara (TTS)</h3>
|
|
<p class="text-sm text-gray-500 mt-1">Konversi teks ke suara otomatis</p>
|
|
</div>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Regular Announcement Form -->
|
|
<div id="reguler-form" class="mode-form">
|
|
<div class="mb-6">
|
|
<label for="message" class="block text-gray-700 font-medium mb-2">Konten Pengumuman</label>
|
|
<div class="relative">
|
|
<textarea name="message" id="message" rows="4" maxlength="500"
|
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition duration-200"
|
|
placeholder="Tulis isi pengumuman Anda di sini..."></textarea>
|
|
<div class="absolute bottom-2 right-2 bg-white px-2 text-xs text-gray-500 rounded">
|
|
<span id="char-count">0</span>/500
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- TTS Announcement Form -->
|
|
<div id="tts-form" class="mode-form hidden">
|
|
<div class="mb-6">
|
|
<label for="tts_text" class="block text-gray-700 font-medium mb-2">Teks untuk Suara</label>
|
|
<div class="relative">
|
|
<textarea name="tts_text" id="tts_text" rows="4" maxlength="1000"
|
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent transition duration-200"
|
|
placeholder="Masukkan teks yang akan diubah menjadi suara..."></textarea>
|
|
<div class="absolute bottom-2 right-2 bg-white px-2 text-xs text-gray-500 rounded">
|
|
<span id="tts-char-count">0</span>/1000
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<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">Pilihan Suara</label>
|
|
<div class="relative">
|
|
<select name="tts_voice" id="tts_voice"
|
|
class="appearance-none w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent transition duration-200 pr-10 bg-white">
|
|
<option value="id-id">Bahasa Indonesia</option>
|
|
<option value="en-us">English (Amerika)</option>
|
|
<option value="en-gb">English (Inggris)</option>
|
|
<option value="ja-jp">日本語 (Jepang)</option>
|
|
</select>
|
|
<div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-3 text-gray-700">
|
|
<i class="fas fa-chevron-down"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label for="tts_speed" class="block text-gray-700 font-medium mb-2">Kecepatan Bicara</label>
|
|
<div class="flex items-center space-x-4">
|
|
<i class="fas fa-turtle text-gray-400"></i>
|
|
<input type="range" name="tts_speed" id="tts_speed" min="-10" max="10" value="0"
|
|
class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-purple-600">
|
|
<i class="fas fa-hare text-gray-400"></i>
|
|
</div>
|
|
<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 class="mb-6">
|
|
<button type="button" id="preview-tts"
|
|
class="px-5 py-2.5 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition duration-300 shadow-md flex items-center">
|
|
<i class="fas fa-play-circle mr-2"></i> Dengarkan Preview
|
|
</button>
|
|
<div class="mt-3 flex items-center">
|
|
<audio id="tts-preview" controls class="w-full max-w-md hidden"></audio>
|
|
<div id="preview-loading" class="hidden items-center text-purple-600 ml-3">
|
|
<i class="fas fa-spinner fa-spin mr-2"></i>
|
|
<span>Memproses audio...</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Ruangan Selection -->
|
|
<div class="mb-8">
|
|
<div class="flex justify-between items-center mb-3">
|
|
<label class="block text-gray-700 font-medium">Tujuan Pengumuman</label>
|
|
<div class="flex space-x-3">
|
|
<button type="button" id="select-all"
|
|
class="text-sm text-blue-600 hover:text-blue-800 flex items-center">
|
|
<i class="fas fa-check-circle mr-1"></i> Pilih Semua
|
|
</button>
|
|
<button type="button" id="deselect-all"
|
|
class="text-sm text-gray-600 hover:text-gray-800 flex items-center">
|
|
<i class="fas fa-times-circle mr-1"></i> Hapus Semua
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="border border-gray-200 rounded-lg p-4">
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-3">
|
|
@foreach($ruangan as $room)
|
|
<label class="room-label flex items-center space-x-3 p-3 rounded-lg hover:bg-gray-50 transition duration-200 cursor-pointer">
|
|
<input type="checkbox" name="ruangan[]" value="{{ $room->id }}"
|
|
class="form-checkbox h-5 w-5 text-blue-600 rounded room-checkbox transition duration-200">
|
|
<div>
|
|
<span class="font-medium text-gray-800">{{ $room->nama_ruangan }}</span>
|
|
<div class="flex items-center text-xs text-gray-500 mt-1">
|
|
<i class="fas fa-door-open mr-1"></i>
|
|
<span>{{ $room->kelas->nama_kelas ?? '-' }} • {{ $room->jurusan->nama_jurusan ?? '-' }}</span>
|
|
</div>
|
|
</div>
|
|
</label>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Submit Button -->
|
|
<div class="flex justify-end pt-4 border-t border-gray-100">
|
|
<button type="submit" id="submit-btn"
|
|
class="px-8 py-3 bg-gradient-to-r from-blue-600 to-indigo-700 text-white rounded-lg hover:from-blue-700 hover:to-indigo-800 transition duration-300 shadow-lg flex items-center">
|
|
<i class="fas fa-paper-plane mr-2"></i> Kirim Pengumuman
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Announcements Section -->
|
|
<div class="bg-white rounded-xl shadow-lg overflow-hidden border border-gray-100">
|
|
<!-- Section Header -->
|
|
<div class="bg-gradient-to-r from-gray-50 to-gray-100 px-6 py-4 border-b border-gray-200">
|
|
<div class="flex flex-col md:flex-row justify-between items-start md:items-center">
|
|
<h2 class="text-lg font-semibold text-gray-800">Pengumuman Terakhir</h2>
|
|
<div class="mt-2 md:mt-0 text-sm">
|
|
Menampilkan {{ $announcements->count() }} dari {{ $announcements->total() }} pengumuman
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Section Body -->
|
|
<div class="p-6">
|
|
@if($announcements->isEmpty())
|
|
<div class="text-center py-12">
|
|
<div class="mx-auto w-24 h-24 bg-gray-100 rounded-full flex items-center justify-center mb-4">
|
|
<i class="fas fa-bullhorn text-3xl text-gray-400"></i>
|
|
</div>
|
|
<h3 class="text-lg font-medium text-gray-700">Belum Ada Pengumuman</h3>
|
|
<p class="text-gray-500 mt-1">Mulailah dengan membuat pengumuman baru</p>
|
|
</div>
|
|
@else
|
|
<div class="space-y-4">
|
|
@foreach($announcements as $announcement)
|
|
<div class="announcement-card border border-gray-200 rounded-xl p-5 hover:shadow-md transition duration-200">
|
|
<div class="flex justify-between items-start">
|
|
<div class="flex items-start space-x-4">
|
|
<div class="mt-1">
|
|
@if($announcement->mode === 'reguler')
|
|
<div class="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center">
|
|
<i class="fas fa-align-left text-blue-600"></i>
|
|
</div>
|
|
@else
|
|
<div class="w-10 h-10 rounded-full bg-purple-100 flex items-center justify-center">
|
|
<i class="fas fa-volume-up text-purple-600"></i>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
<div>
|
|
<h3 class="font-medium text-gray-800 line-clamp-2">
|
|
{{ $announcement->message }}
|
|
</h3>
|
|
<div class="flex flex-wrap items-center mt-2 text-sm text-gray-500 space-x-4">
|
|
<div class="flex items-center">
|
|
<i class="fas fa-user-circle mr-1.5"></i>
|
|
<span>{{ $announcement->user->name }}</span>
|
|
</div>
|
|
<div class="flex items-center">
|
|
<i class="fas fa-clock mr-1.5"></i>
|
|
<span>{{ $announcement->sent_at->diffForHumans() }}</span>
|
|
</div>
|
|
<div class="flex items-center">
|
|
<i class="fas fa-door-open mr-1.5"></i>
|
|
<span>{{ count($announcement->ruangan) }} ruangan</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="dropdown relative">
|
|
<button class="dropdown-toggle p-1 rounded-full hover:bg-gray-100 text-gray-400 hover:text-gray-600 transition duration-200">
|
|
<i class="fas fa-ellipsis-v"></i>
|
|
</button>
|
|
<div class="dropdown-menu absolute right-0 mt-1 w-40 bg-white rounded-md shadow-lg py-1 z-10 hidden border border-gray-200">
|
|
<a href="{{ route('announcement.show', $announcement->id) }}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
|
<i class="fas fa-eye mr-2"></i> Detail
|
|
</a>
|
|
<form action="{{ route('announcement.destroy', $announcement->id) }}" method="POST" class="block w-full">
|
|
@csrf
|
|
@method('DELETE')
|
|
<button type="button" onclick="confirmDelete(this)" class="w-full text-left px-4 py-2 text-sm text-red-600 hover:bg-gray-100">
|
|
<i class="fas fa-trash-alt mr-2"></i> Hapus
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
|
|
<!-- Pagination -->
|
|
<div class="mt-6">
|
|
{{ $announcements->links('vendor.pagination.tailwind') }}
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Help Modal -->
|
|
<div id="help-modal" class="fixed inset-0 bg-black bg-opacity-50 z-50 hidden flex items-center justify-center p-4">
|
|
<div class="bg-white rounded-xl max-w-2xl w-full max-h-[90vh] overflow-y-auto">
|
|
<div class="border-b border-gray-200 p-5 flex justify-between items-center">
|
|
<h3 class="text-xl font-semibold text-gray-800">Panduan Penggunaan</h3>
|
|
<button id="close-help" class="text-gray-400 hover:text-gray-600">
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
</div>
|
|
<div class="p-5">
|
|
<div class="space-y-6">
|
|
<div>
|
|
<h4 class="font-medium text-lg text-gray-800 mb-2 flex items-center">
|
|
<span class="w-8 h-8 bg-blue-100 rounded-full flex items-center justify-center mr-3 text-blue-600">
|
|
<i class="fas fa-info-circle"></i>
|
|
</span>
|
|
Tentang Sistem Pengumuman
|
|
</h4>
|
|
<p class="text-gray-600 pl-11">
|
|
Sistem ini memungkinkan Anda mengirim pengumuman ke ruangan terpilih dalam dua format: teks biasa atau suara (TTS).
|
|
Pengumuman akan langsung diterima oleh perangkat di ruangan tujuan.
|
|
</p>
|
|
</div>
|
|
|
|
<div>
|
|
<h4 class="font-medium text-lg text-gray-800 mb-2 flex items-center">
|
|
<span class="w-8 h-8 bg-purple-100 rounded-full flex items-center justify-center mr-3 text-purple-600">
|
|
<i class="fas fa-volume-up"></i>
|
|
</span>
|
|
Mode Text-to-Speech (TTS)
|
|
</h4>
|
|
<ul class="text-gray-600 pl-11 space-y-2 list-disc list-inside">
|
|
<li>Gunakan untuk pengumuman audio yang akan dibacakan oleh sistem</li>
|
|
<li>Anda bisa memilih jenis suara dan kecepatan bicara</li>
|
|
<li>Gunakan tombol preview untuk mendengarkan sebelum mengirim</li>
|
|
<li>Maksimal 1000 karakter per pengumuman</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div>
|
|
<h4 class="font-medium text-lg text-gray-800 mb-2 flex items-center">
|
|
<span class="w-8 h-8 bg-green-100 rounded-full flex items-center justify-center mr-3 text-green-600">
|
|
<i class="fas fa-lightbulb"></i>
|
|
</span>
|
|
Tips Penggunaan
|
|
</h4>
|
|
<ul class="text-gray-600 pl-11 space-y-2 list-disc list-inside">
|
|
<li>Untuk pengumuman penting, gunakan mode TTS untuk memastikan didengar</li>
|
|
<li>Gunakan bahasa yang jelas dan singkat</li>
|
|
<li>Periksa kembali ruangan tujuan sebelum mengirim</li>
|
|
<li>Anda bisa melihat riwayat pengumuman di menu Riwayat</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="border-t border-gray-200 p-5 flex justify-end">
|
|
<button id="close-help-btn" class="px-5 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition duration-200">
|
|
Mengerti
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- SweetAlert CDN -->
|
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
|
|
|
<!-- Custom Script -->
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Mode selector with enhanced UI
|
|
const modeOptions = document.querySelectorAll('.mode-option');
|
|
modeOptions.forEach(option => {
|
|
option.addEventListener('click', function() {
|
|
modeOptions.forEach(opt => {
|
|
opt.querySelector('div').classList.remove('border-blue-400', 'border-purple-400', 'bg-blue-50', 'bg-purple-50');
|
|
});
|
|
|
|
const selectedMode = this.querySelector('input').dataset.mode;
|
|
const optionDiv = this.querySelector('div');
|
|
|
|
if (selectedMode === 'reguler') {
|
|
optionDiv.classList.add('border-blue-400', 'bg-blue-50');
|
|
} else {
|
|
optionDiv.classList.add('border-purple-400', 'bg-purple-50');
|
|
}
|
|
|
|
// Toggle forms
|
|
document.querySelectorAll('.mode-form').forEach(form => {
|
|
form.classList.toggle('hidden', form.id !== `${selectedMode}-form`);
|
|
});
|
|
|
|
// Update room checkboxes name based on mode
|
|
document.querySelectorAll('.room-checkbox').forEach(checkbox => {
|
|
checkbox.name = selectedMode === 'tts' ? 'tts_ruangan[]' : 'ruangan[]';
|
|
});
|
|
});
|
|
});
|
|
|
|
// Initialize first mode as selected
|
|
document.querySelector('.mode-option input[checked]').dispatchEvent(new Event('click'));
|
|
|
|
// Character counter with progress circle
|
|
const setupCharCounter = (textarea, counter, max) => {
|
|
textarea.addEventListener('input', function() {
|
|
const count = this.value.length;
|
|
counter.textContent = count;
|
|
|
|
// Update progress color
|
|
const percentage = (count / max) * 100;
|
|
if (percentage > 90) {
|
|
counter.classList.add('text-red-500');
|
|
counter.classList.remove('text-yellow-500', 'text-gray-500');
|
|
} else if (percentage > 70) {
|
|
counter.classList.add('text-yellow-500');
|
|
counter.classList.remove('text-red-500', 'text-gray-500');
|
|
} else {
|
|
counter.classList.add('text-gray-500');
|
|
counter.classList.remove('text-red-500', 'text-yellow-500');
|
|
}
|
|
});
|
|
};
|
|
|
|
setupCharCounter(document.getElementById('message'), document.getElementById('char-count'), 500);
|
|
setupCharCounter(document.getElementById('tts_text'), document.getElementById('tts-char-count'), 1000);
|
|
|
|
// Room selection with enhanced UI
|
|
document.getElementById('select-all').addEventListener('click', function() {
|
|
document.querySelectorAll('.room-checkbox').forEach(checkbox => {
|
|
checkbox.checked = true;
|
|
checkbox.closest('.room-label').classList.add('bg-blue-50', 'border-blue-200');
|
|
});
|
|
});
|
|
|
|
document.getElementById('deselect-all').addEventListener('click', function() {
|
|
document.querySelectorAll('.room-checkbox').forEach(checkbox => {
|
|
checkbox.checked = false;
|
|
checkbox.closest('.room-label').classList.remove('bg-blue-50', 'border-blue-200');
|
|
});
|
|
});
|
|
|
|
// Room label click handler
|
|
document.querySelectorAll('.room-label').forEach(label => {
|
|
label.addEventListener('click', function(e) {
|
|
if (!e.target.classList.contains('room-checkbox')) {
|
|
const checkbox = this.querySelector('.room-checkbox');
|
|
checkbox.checked = !checkbox.checked;
|
|
|
|
if (checkbox.checked) {
|
|
this.classList.add('bg-blue-50', 'border-blue-200');
|
|
} else {
|
|
this.classList.remove('bg-blue-50', 'border-blue-200');
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// TTS Preview with enhanced UI
|
|
document.getElementById('preview-tts').addEventListener('click', function() {
|
|
const text = document.getElementById('tts_text').value.trim();
|
|
const voice = document.getElementById('tts_voice').value;
|
|
const speed = document.getElementById('tts_speed').value;
|
|
|
|
if (!text) {
|
|
Swal.fire({
|
|
icon: 'warning',
|
|
title: 'Teks Kosong',
|
|
text: 'Silakan masukkan teks untuk dipreview',
|
|
confirmButtonColor: '#6366f1',
|
|
backdrop: 'rgba(99, 102, 241, 0.1)'
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Show loading
|
|
const previewBtn = this;
|
|
const loadingIndicator = document.getElementById('preview-loading');
|
|
const audioPlayer = document.getElementById('tts-preview');
|
|
|
|
previewBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> Memproses...';
|
|
previewBtn.disabled = true;
|
|
loadingIndicator.classList.remove('hidden');
|
|
audioPlayer.classList.add('hidden');
|
|
|
|
// Call TTS API
|
|
fetch("{{ route('announcement.ttsPreview') }}", {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
|
'Accept': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
text: text,
|
|
voice: voice,
|
|
speed: speed
|
|
})
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network response was not ok');
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
if (data.audio_url) {
|
|
audioPlayer.src = data.audio_url;
|
|
audioPlayer.classList.remove('hidden');
|
|
loadingIndicator.classList.add('hidden');
|
|
audioPlayer.play();
|
|
|
|
// Show success toast
|
|
const Toast = Swal.mixin({
|
|
toast: true,
|
|
position: 'top-end',
|
|
showConfirmButton: false,
|
|
timer: 3000,
|
|
timerProgressBar: true,
|
|
didOpen: (toast) => {
|
|
toast.addEventListener('mouseenter', Swal.stopTimer)
|
|
toast.addEventListener('mouseleave', Swal.resumeTimer)
|
|
}
|
|
});
|
|
|
|
Toast.fire({
|
|
icon: 'success',
|
|
title: 'Preview audio siap!'
|
|
});
|
|
} else {
|
|
throw new Error(data.message || 'Gagal menghasilkan audio');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
Swal.fire({
|
|
icon: 'error',
|
|
title: 'Gagal Membuat Preview',
|
|
text: error.message || 'Terjadi kesalahan saat menghasilkan audio',
|
|
confirmButtonColor: '#6366f1',
|
|
backdrop: 'rgba(99, 102, 241, 0.1)'
|
|
});
|
|
})
|
|
.finally(() => {
|
|
previewBtn.innerHTML = '<i class="fas fa-play-circle mr-2"></i> Dengarkan Preview';
|
|
previewBtn.disabled = false;
|
|
loadingIndicator.classList.add('hidden');
|
|
});
|
|
});
|
|
|
|
// Form submission with enhanced validation
|
|
document.getElementById('announcementForm').addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
const form = this;
|
|
const formData = new FormData(form);
|
|
const selectedRooms = document.querySelectorAll('.room-checkbox:checked');
|
|
const mode = document.querySelector('input[name="mode"]:checked').value;
|
|
const messageField = mode === 'reguler' ? 'message' : 'tts_text';
|
|
const message = formData.get(messageField);
|
|
|
|
// Validation
|
|
if (selectedRooms.length === 0) {
|
|
Swal.fire({
|
|
icon: 'warning',
|
|
title: 'Ruangan Belum Dipilih',
|
|
text: 'Silakan pilih setidaknya satu ruangan tujuan',
|
|
confirmButtonColor: '#6366f1',
|
|
backdrop: 'rgba(99, 102, 241, 0.1)'
|
|
});
|
|
|
|
// Scroll to room selection
|
|
document.querySelector('.room-checkbox').closest('.mb-8').scrollIntoView({
|
|
behavior: 'smooth',
|
|
block: 'center'
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (!message || message.trim().length === 0) {
|
|
Swal.fire({
|
|
icon: 'warning',
|
|
title: 'Konten Kosong',
|
|
text: `Silakan isi ${mode === 'reguler' ? 'pesan pengumuman' : 'teks untuk TTS'}`,
|
|
confirmButtonColor: '#6366f1',
|
|
backdrop: 'rgba(99, 102, 241, 0.1)'
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Confirmation dialog
|
|
Swal.fire({
|
|
title: 'Konfirmasi Pengiriman',
|
|
html: `
|
|
<div class="text-left">
|
|
<p class="mb-2">Anda akan mengirim pengumuman <span class="font-semibold">${mode === 'reguler' ? 'teks' : 'suara (TTS)'}</span> ke:</p>
|
|
<ul class="list-disc list-inside mb-4 max-h-40 overflow-y-auto">
|
|
${Array.from(selectedRooms).map(room => {
|
|
const roomLabel = room.closest('.room-label').querySelector('span').textContent;
|
|
return `<li>${roomLabel}</li>`;
|
|
}).join('')}
|
|
</ul>
|
|
<p class="text-sm text-gray-500">Pastikan informasi sudah benar sebelum mengirim</p>
|
|
</div>
|
|
`,
|
|
icon: 'question',
|
|
showCancelButton: true,
|
|
confirmButtonColor: '#6366f1',
|
|
cancelButtonColor: '#d33',
|
|
confirmButtonText: 'Ya, Kirim Sekarang',
|
|
cancelButtonText: 'Periksa Kembali',
|
|
backdrop: 'rgba(99, 102, 241, 0.1)',
|
|
width: '32rem'
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
// Show loading
|
|
const submitBtn = document.getElementById('submit-btn');
|
|
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> Mengirim...';
|
|
submitBtn.disabled = true;
|
|
|
|
// Submit form
|
|
fetch(form.action, {
|
|
method: 'POST',
|
|
body: formData,
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
|
}
|
|
})
|
|
.then(response => {
|
|
if (response.redirected) {
|
|
window.location.href = response.url;
|
|
} else {
|
|
return response.json();
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
Swal.fire({
|
|
icon: 'error',
|
|
title: 'Gagal Mengirim',
|
|
text: error.message || 'Terjadi kesalahan saat mengirim pengumuman',
|
|
confirmButtonColor: '#6366f1',
|
|
backdrop: 'rgba(99, 102, 241, 0.1)'
|
|
});
|
|
})
|
|
.finally(() => {
|
|
submitBtn.innerHTML = '<i class="fas fa-paper-plane mr-2"></i> Kirim Pengumuman';
|
|
submitBtn.disabled = false;
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
// Help modal
|
|
const helpModal = document.getElementById('help-modal');
|
|
document.getElementById('help-btn').addEventListener('click', () => {
|
|
helpModal.classList.remove('hidden');
|
|
document.body.style.overflow = 'hidden';
|
|
});
|
|
|
|
document.getElementById('close-help').addEventListener('click', () => {
|
|
helpModal.classList.add('hidden');
|
|
document.body.style.overflow = 'auto';
|
|
});
|
|
|
|
document.getElementById('close-help-btn').addEventListener('click', () => {
|
|
helpModal.classList.add('hidden');
|
|
document.body.style.overflow = 'auto';
|
|
});
|
|
|
|
// Dropdown menu for announcement cards
|
|
document.querySelectorAll('.dropdown-toggle').forEach(toggle => {
|
|
toggle.addEventListener('click', function(e) {
|
|
e.stopPropagation();
|
|
const menu = this.nextElementSibling;
|
|
document.querySelectorAll('.dropdown-menu').forEach(m => {
|
|
if (m !== menu) m.classList.add('hidden');
|
|
});
|
|
menu.classList.toggle('hidden');
|
|
});
|
|
});
|
|
|
|
// Close dropdowns when clicking outside
|
|
document.addEventListener('click', function() {
|
|
document.querySelectorAll('.dropdown-menu').forEach(menu => {
|
|
menu.classList.add('hidden');
|
|
});
|
|
});
|
|
|
|
// Confirm delete function
|
|
function confirmDelete(form) {
|
|
Swal.fire({
|
|
title: 'Hapus Pengumuman?',
|
|
text: "Anda tidak akan bisa mengembalikan data ini!",
|
|
icon: 'warning',
|
|
showCancelButton: true,
|
|
confirmButtonColor: '#6366f1',
|
|
cancelButtonColor: '#d33',
|
|
confirmButtonText: 'Ya, Hapus!',
|
|
cancelButtonText: 'Batal',
|
|
backdrop: 'rgba(99, 102, 241, 0.1)'
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
form.closest('form').submit();
|
|
}
|
|
});
|
|
};
|
|
});
|
|
</script>
|
|
@endsection |