MIF_E31222307/resources/views/layoutuser/app.blade.php

531 lines
22 KiB
PHP

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>HeartChoice</title>
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<meta content="" name="keywords">
<meta content="" name="description">
<!-- Favicon -->
<link href="{{ asset('logo/baru/dutdut.png') }}" rel="icon">
<!-- Google Web Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;500&family=Roboto:wght@500;700;900&display=swap" rel="stylesheet">
<!-- Icon Font Stylesheet -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.0/css/all.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.4.1/font/bootstrap-icons.css" rel="stylesheet">
<!-- Libraries Stylesheet -->
<link href="{{ asset('assetss/lib/animate/animate.min.css') }}" rel="stylesheet">
<link href="{{ asset('assetss/lib/owlcarousel/assets/owl.carousel.min.css') }}" rel="stylesheet">
<link href="{{ asset('assetss/lib/tempusdominus/css/tempusdominus-bootstrap-4.min.css') }}" rel="stylesheet" />
<!-- Customized Bootstrap Stylesheet -->
<link href="{{ asset('assetss/css/bootstrap.min.css') }}" rel="stylesheet">
<!-- Template Stylesheet -->
<link href="{{ asset('assetss/css/style.css') }}" rel="stylesheet">
</head>
<body>
<!-- Spinner Start -->
<div id="spinner" class="show bg-white position-fixed translate-middle w-100 vh-100 top-50 start-50 d-flex align-items-center justify-content-center">
<div class="spinner-grow text-primary" style="width: 3rem; height: 3rem;" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<!-- Spinner End -->
<!-- Topbar Start -->
{{-- <div class="container-fluid bg-light p-0 wow fadeIn" data-wow-delay="0.1s">
<div class="row gx-0 d-none d-lg-flex">
<div class="col-lg-7 px-5 text-start">
<div class="h-100 d-inline-flex align-items-center py-3 me-4">
<small class="fa fa-map-marker-alt text-primary me-2"></small>
<small>123 Street, New York, USA</small>
</div>
<div class="h-100 d-inline-flex align-items-center py-3">
<small class="far fa-clock text-primary me-2"></small>
<small>Mon - Fri : 09.00 AM - 09.00 PM</small>
</div>
</div>
<div class="col-lg-5 px-5 text-end">
<div class="h-100 d-inline-flex align-items-center py-3 me-4">
<small class="fa fa-phone-alt text-primary me-2"></small>
<small>+012 345 6789</small>
</div>
<div class="h-100 d-inline-flex align-items-center">
<a class="btn btn-sm-square rounded-circle bg-white text-primary me-1" href=""><i class="fab fa-facebook-f"></i></a>
<a class="btn btn-sm-square rounded-circle bg-white text-primary me-1" href=""><i class="fab fa-twitter"></i></a>
<a class="btn btn-sm-square rounded-circle bg-white text-primary me-1" href=""><i class="fab fa-linkedin-in"></i></a>
<a class="btn btn-sm-square rounded-circle bg-white text-primary me-0" href=""><i class="fab fa-instagram"></i></a>
</div>
</div>
</div>
</div> --}}
<!-- Topbar End -->
<!-- Navbar Start -->
<nav class="navbar navbar-expand-lg bg-white navbar-light sticky-top p-0 wow fadeIn" data-wow-delay="0.1s">
@include('layoutuser.header')
</nav>
<!-- Navbar End -->
<!-- Header Start -->
<!-- Header End -->
<!-- About Start -->
<div id="alert-container" class="position-fixed top-0 start-50 translate-middle-x p-3" style="z-index: 1050; display: none;">
<!-- Alert akan muncul di sini -->
</div>
@yield('content')
<!-- Testimonial End -->
<!-- Footer Start -->
<div class="container-fluid bg-dark text-light footer mt-5 pt-5 wow fadeIn" data-wow-delay="0.1s">
@include('layoutuser.footer')
</div>
<!-- Footer End -->
<!-- Back to Top -->
<a href="#" class="btn btn-lg btn-primary btn-lg-square rounded-circle back-to-top"><i class="bi bi-arrow-up"></i></a>
<!-- JavaScript Libraries -->
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="{{ asset('assetss/lib/wow/wow.min.js')}}"></script>
<script src="{{ asset('assetss/lib/easing/easing.min.js')}}"></script>
<script src="{{ asset('assetss/lib/waypoints/waypoints.min.js')}}"></script>
<script src="{{ asset('assetss/lib/counterup/counterup.min.js')}}"></script>
<script src="{{ asset('assetss/lib/owlcarousel/owl.carousel.min.js')}}"></script>
<script src="{{ asset('assetss/lib/tempusdominus/js/moment.min.js')}}"></script>
<script src="{{ asset('assetss/lib/tempusdominus/js/moment-timezone.min.js')}}"></script>
<script src="{{ asset('assetss/lib/tempusdominus/js/tempusdominus-bootstrap-4.min.js')}}"></script>
<!-- Template Javascript -->
<script src="{{ asset('assetss/js/main.js') }}"></script>
<!-- Alert Script -->
@auth
<script>
let alertEnabled = {{ auth()->user()->alertSetting->is_enabled ?? 'true' }};
let lastAlertTime = 0; // Untuk mencegah spam alert
let lastNotificationTime = 0; // Untuk mencegah spam notifikasi
// Audio untuk notifikasi
const notificationAudio = new Audio('{{ asset("audio/notification.mp3") }}');
notificationAudio.volume = 0.5; // Volume 50%
// Fungsi untuk memutar suara notifikasi dengan kontrol spam
function playNotificationSound(force = false) {
const now = Date.now();
// Jika bukan force dan belum 5 detik sejak suara terakhir, skip
if (!force && (now - lastNotificationTime) < 5000) {
return;
}
try {
// Get current sound setting
const currentSound = localStorage.getItem('notification_sound') || 'default';
const soundEnabled = localStorage.getItem('notification_sound_enabled') !== 'false';
const autoSoundEnabled = localStorage.getItem('notification_auto_sound_enabled') === 'true';
const volume = localStorage.getItem('notification_volume') || 0.3;
// Jika bukan force dan auto sound dinonaktifkan, skip
if (!force && !autoSoundEnabled) {
return;
}
if (!soundEnabled) return;
const audio = new Audio(`/audio/${currentSound}.mp3`);
audio.volume = volume;
audio.play().catch(e => {
console.log('Audio tidak bisa diputar:', e);
});
lastNotificationTime = now;
} catch (error) {
console.log('Error memutar audio:', error);
}
}
// Toggle alert
function toggleAlert() {
fetch('{{ route("user.alert-settings.toggle") }}', {
method: 'POST',
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}',
'Content-Type': 'application/json',
}
})
.then(response => response.json())
.then(data => {
alertEnabled = data.is_enabled;
updateAlertButton();
if (data.is_enabled) {
startAlertCheck();
} else {
stopAlertCheck();
}
});
}
// Update tombol alert
function updateAlertButton() {
const btn = document.getElementById('alert-toggle-btn');
if (btn) {
btn.innerHTML = alertEnabled ?
'<i class="fas fa-bell text-warning"></i>' :
'<i class="fas fa-bell-slash text-muted"></i>';
btn.title = alertEnabled ? 'Alert Aktif' : 'Alert Nonaktif';
}
}
// Cek alert setiap menit
let alertInterval;
function startAlertCheck() {
if (alertInterval) clearInterval(alertInterval);
alertInterval = setInterval(checkAlerts, 60000); // 1 menit
checkAlerts(); // Cek sekali saat start
}
function stopAlertCheck() {
if (alertInterval) {
clearInterval(alertInterval);
alertInterval = null;
}
}
// Cek dan tampilkan alert
function checkAlerts() {
if (!alertEnabled) return;
fetch('{{ route("user.alert-settings.get-alerts") }}')
.then(response => response.json())
.then(data => {
data.alerts.forEach(alert => {
showAlert(alert);
});
});
}
// Tampilkan alert
function showAlert(alert) {
const now = Date.now();
// Mencegah spam alert - minimal 30 detik antara alert
if ((now - lastAlertTime) < 30000) {
return;
}
// Gunakan browser notification jika tersedia
if (!showBrowserNotification(alert.nama, alert.alert_text)) {
// Fallback ke visual alert
const container = document.getElementById('alert-container');
const alertHtml = `
<div class="alert alert-info alert-dismissible fade show" role="alert">
<i class="fas fa-clock me-2"></i>
<strong>${alert.nama}:</strong> ${alert.alert_text}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
`;
container.innerHTML = alertHtml;
container.style.display = 'block';
// Putar suara notifikasi hanya untuk alert waktu makan
playNotificationSound(true);
// Auto hide setelah 10 detik
setTimeout(() => {
container.style.display = 'none';
}, 10000);
}
lastAlertTime = now;
}
// Initialize
document.addEventListener('DOMContentLoaded', function() {
// Register Service Worker untuk notifikasi background
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('Service Worker registered:', registration);
})
.catch(error => {
console.log('Service Worker registration failed:', error);
});
}
// Cek permission saat halaman dimuat
if ('Notification' in window) {
notificationPermission = Notification.permission;
// Tampilkan request permission jika belum diatur
if (notificationPermission === 'default') {
setTimeout(() => {
showPermissionRequest();
}, 2000); // Delay 2 detik
}
}
// Initialize alert system
updateAlertButton();
if (alertEnabled) {
startAlertCheck();
}
// Load notifications tanpa memutar suara otomatis
loadNotifications(false);
updateNotificationCount();
});
</script>
@endauth
<!-- Notification Script -->
@auth
<script>
// Browser Notification System
let notificationPermission = 'default'; // default, granted, denied
// Request permission untuk browser notifications
async function requestNotificationPermission() {
if (!('Notification' in window)) {
console.log('Browser tidak mendukung notifications');
return false;
}
if (Notification.permission === 'granted') {
notificationPermission = 'granted';
return true;
}
if (Notification.permission === 'denied') {
notificationPermission = 'denied';
return false;
}
// Request permission
const permission = await Notification.requestPermission();
notificationPermission = permission;
if (permission === 'granted') {
showPermissionSuccess();
return true;
} else {
showPermissionDenied();
return false;
}
}
// Tampilkan notifikasi browser
function showBrowserNotification(title, message, icon = null) {
if (notificationPermission !== 'granted') {
return false;
}
const notification = new Notification(title, {
body: message,
icon: icon || '{{ asset("logo/baru/dutdut.png") }}',
badge: '{{ asset("logo/baru/dutdut.png") }}',
tag: 'heartchoice-notification',
requireInteraction: false,
silent: false // Akan memutar suara sistem
});
// Auto close setelah 5 detik
setTimeout(() => {
notification.close();
}, 5000);
// Click event
notification.onclick = function() {
window.focus();
notification.close();
};
return true;
}
// Fallback ke audio jika browser notification tidak tersedia
function showFallbackNotification(title, message) {
// Tampilkan alert visual
const container = document.getElementById('alert-container');
const alertHtml = `
<div class="alert alert-info alert-dismissible fade show" role="alert">
<i class="fas fa-bell me-2"></i>
<strong>${title}:</strong> ${message}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
`;
container.innerHTML = alertHtml;
container.style.display = 'block';
// Putar suara hanya jika benar-benar diperlukan
playNotificationSound(true);
// Auto hide setelah 10 detik
setTimeout(() => {
container.style.display = 'none';
}, 10000);
}
// Fungsi utama untuk menampilkan notifikasi
function showNotification(title, message, type = 'info') {
// Coba browser notification dulu
if (!showBrowserNotification(title, message)) {
// Fallback ke visual + audio
showFallbackNotification(title, message);
}
}
// UI untuk permission
function showPermissionRequest() {
const container = document.getElementById('alert-container');
const alertHtml = `
<div class="alert alert-warning alert-dismissible fade show" role="alert">
<i class="fas fa-bell me-2"></i>
<strong>Aktifkan Notifikasi:</strong> Untuk pengalaman terbaik, izinkan notifikasi dari HeartChoice.
<button type="button" class="btn btn-sm btn-primary ms-2" onclick="requestNotificationPermission()">
<i class="fas fa-check me-1"></i>Aktifkan
</button>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
`;
container.innerHTML = alertHtml;
container.style.display = 'block';
}
function showPermissionSuccess() {
const container = document.getElementById('alert-container');
const alertHtml = `
<div class="alert alert-success alert-dismissible fade show" role="alert">
<i class="fas fa-check-circle me-2"></i>
<strong>Berhasil!</strong> Notifikasi browser telah diaktifkan.
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
`;
container.innerHTML = alertHtml;
container.style.display = 'block';
setTimeout(() => {
container.style.display = 'none';
}, 3000);
}
function showPermissionDenied() {
const container = document.getElementById('alert-container');
const alertHtml = `
<div class="alert alert-info alert-dismissible fade show" role="alert">
<i class="fas fa-info-circle me-2"></i>
<strong>Info:</strong> Notifikasi browser dinonaktifkan. Anda masih akan mendapat notifikasi visual dan suara.
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
`;
container.innerHTML = alertHtml;
container.style.display = 'block';
setTimeout(() => {
container.style.display = 'none';
}, 5000);
}
function loadNotifications(playSound = false) {
fetch('{{ route("user.notifications.latest") }}')
.then(response => response.json())
.then(data => {
const container = document.getElementById('notification-list');
if (data.notifications.length > 0) {
let html = '';
let hasUnread = false;
data.notifications.forEach(notification => {
const isUnread = !notification.is_read;
if (isUnread) hasUnread = true;
const typeClass = notification.type === 'reminder' ? 'warning' :
(notification.type === 'success' ? 'success' : 'info');
html += `
<a href="#" class="dropdown-item ${isUnread ? 'bg-light' : ''}" onclick="markAsRead(${notification.id})">
<div class="d-flex align-items-center">
<div class="flex-shrink-0">
<span class="badge bg-${typeClass} rounded-pill">${notification.type}</span>
</div>
<div class="flex-grow-1 ms-3">
<h6 class="mb-1 ${isUnread ? 'fw-bold' : ''}">${notification.title}</h6>
<p class="mb-1 small">${notification.message}</p>
<small class="text-muted">${new Date(notification.created_at).toLocaleString()}</small>
</div>
</div>
</a>
`;
});
container.innerHTML = html;
// Putar suara hanya jika diminta dan ada notifikasi baru
if (playSound && hasUnread) {
playNotificationSound(true);
}
} else {
container.innerHTML = `
<div class="text-center py-3">
<i class="fas fa-bell-slash text-muted"></i>
<small class="d-block mt-1 text-muted">Tidak ada notifikasi</small>
</div>
`;
}
});
}
function updateNotificationCount() {
fetch('{{ route("user.notifications.unread-count") }}')
.then(response => response.json())
.then(data => {
const badge = document.getElementById('notification-badge');
if (badge) {
if (data.count > 0) {
badge.textContent = data.count;
badge.style.display = 'inline';
} else {
badge.style.display = 'none';
}
}
});
}
function markAsRead(id) {
fetch(`/user/notifications/${id}/mark-read`, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}',
'Content-Type': 'application/json',
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
loadNotifications(false); // Tidak memutar suara saat mark as read
updateNotificationCount();
}
});
}
</script>
@endauth
</body>
</html>