531 lines
22 KiB
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> |