ikinci temizlik tamamlandı

This commit is contained in:
Ümit Tunç
2026-04-28 21:15:09 +03:00
parent f80443aec0
commit 37e7296527
8313 changed files with 2400677 additions and 0 deletions
+635
View File
@@ -0,0 +1,635 @@
<?php
if(getisset("ajax")) {
?>
@include("admin-ajax.{$_GET['ajax']}")
<?php
exit();
} ?>
<?php if(getisset("ajax2")) { //blade ajax system
?>
@if(getisset("cache"))
@includeCache("{$_GET['ajax2']}")
@else
@include("{$_GET['ajax2']}")
@endif
<?php
exit();
} ?>
@php
$permissions = userPermissions();
@endphp
<?php $u = u(); ?>
<!DOCTYPE HTML>
<html lang="{{App::getLocale()}}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>{!! strip_tags($__env->yieldContent('title','')) !!}</title>
<link rel="manifest" href="/assets/manifest.json">
<meta name="author" content="Truncgil Technology">
<meta property="og:title" content="">
<meta property="og:site_name" content="https://www.truncgil.com.tr/">
<meta property="og:description" content="">
<meta property="og:type" content="app">
<meta property="og:url" content>
<meta property="og:image" content>
<div class="header-zone">
<link rel="apple-touch-icon" sizes="180x180" href="{{url("assets/favicon.png")}}">
<link rel="shortcut icon" href="{{url("assets/favicon.png")}}" type="image/png">
<meta name="csrf-token" content="{{ csrf_token() }}">
<meta name="theme-color" content="#fff"/>
<meta name="description" content="{!! strip_tags($__env->yieldContent('title','')) !!}">
<!-- Favicon -->
<link rel="icon" href="/assets/favicon.png" type="image/png">
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(function(registration) {
console.log('Service Worker registered with scope:', registration.scope);
})
.catch(function(error) {
console.log('Service Worker registration failed:', error);
});
}
</script>
@include("admin.inc.plugins")
@yield('scripts')
</div>
</head>
<body>
@guest
@yield("content")
@else
<div id="page-container"
@if(isset($contents))
class="sidebar-o enable-page-overlay side-scroll page-header-fixed page-header-glass side-trans-enabled sidebar-inverse"
@endif
>
<aside id="side-overlay">
<div class="content-header content-header-fullrow">
<div class="content-header-section align-parent">
<button type="button" class="btn btn-circle btn-dual-secondary align-v-r" data-toggle="layout" data-action="side_overlay_close">
<i class="fa fa-times text-danger"></i>
</button>
<div class="content-header-item">
<a class="align-middle text-primary-dark font-w600" href="#">
{{ Auth::user()->name }} {{ Auth::user()->surname }}
</a>
</div>
</div>
</div>
@include("admin.inc.side-overlay")
</aside>
@if(isset($contents))
<nav id="sidebar">
<div class="sidebar-content">
<div class="content-side content-side-full content-side-user px-10 align-parent">
<!-- Visible only in mini mode -->
<div class="sidebar-mini-visible-b align-v animated fadeIn">
<a href="{{url("admin")}}">
<img class="img-fluid" src="{{ url("assets/logo.svg") }}" alt="">
</a>
</div>
<!-- END Visible only in mini mode -->
<!-- Visible only in normal mode -->
<div class="sidebar-mini-hidden-b text-center">
<a class="img-link" href="{{url("admin")}}">
<img class="img-fluid" src="{{ url("assets/logo.svg") }}" alt="">
</a>
<a class="text-center text-dual-primary-dark font-size-xs font-w600"
href="#">{{ Auth::user()->name }} {{ Auth::user()->surname }}</a>
<div class="text-center badge badge-success">{{ Auth::user()->level }}</div>
<div class="text-center badge badge-info">{{ Auth::user()->subcontructer }}</div>
<ul class="list-inline mt-10">
<li class="list-inline-item">
</li>
<li class="list-inline-item">
<!-- Layout API, functionality initialized in Template._uiApiLayout() -->
<a class="text-dual-primary-dark" data-toggle="layout"
data-action="sidebar_style_inverse_toggle" href="javascript:void(0)">
<i class="si si-drop"></i>
</a>
</li>
<li class="list-inline-item">
<a class="text-dual-primary-dark" href="{{url("logout")}}">
<i class="si si-logout"></i>
</a>
</li>
<li class="list-inline-item">
</li>
</ul>
</div>
<!-- END Visible only in normal mode -->
</div>
@include("admin.inc.menu")
</div>
</nav>
@include("admin.inc.header")
@endif
<div class="main-container">
<div class="">
@if (View::hasSection('title'))
<div class="bg-image d-none" >
<div class="bg-white-op-90">
<div class="content content-full content-top">
<h1 class="text-center">@yield("title")<br /> </h1>
<div class="text-center d-none">@yield("desc")</div>
</div>
</div>
</div>
@endif
<div class="content-ajax" style="margin-top:70px">
@yield("content")
</div>
</div>
</div>
<div class="clearfix"></div>
@include('admin.inc.feedback-modal')
<footer id="page-footer" class="t-center" style=" background: gray;
color: white;
padding: 5px 10px;
position: fixed;
bottom: 0px;
right: 0px;
width: 100%;
text-align: right;
font-size: 12px;">
<div class="footer-status"></div>
</footer>
</div>
@endguest
<!--
<link rel="stylesheet" href="//cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css" />
<script type="text/javascript" src="//cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
-->
@include("admin.inc.script")
<style type="text/css">
.hidden {
display:none !important;
}
.visible {
display:block !important;
}
.hidden-upload {
display:none;
}
.table-responsive {
/* background: url(back.png) white center center / contain no-repeat !important; */
/* background-attachment: fixed !important; */
background-size: 20% !important;
background-position: center !important;
}
.dz-filename {
white-space:normal !important;
height: 74px;
}
</style>
<div class="modal fade" id="modal-popin" tabindex="-1" role="dialog" aria-labelledby="modal-popin" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-popin" role="document">
<div class="modal-content">
<div class="block block-themed block-transparent mb-0">
<div class="block-header bg-primary-dark">
<h3 class="block-title"></h3>
<div class="block-options">
<button type="button" class="btn-block-option" data-dismiss="modal" aria-label="Close">
<i class="si si-close"></i>
</button>
</div>
</div>
<div class="block-content">
</div>
</div>
<div class="modal-footer">
<button class="btn btn-alt-secondary" data-dismiss="modal">{{__('Hayır')}}</button>
<a href="#" class="btn btn-alt-success tamam" data-dismiss="modal">
<i class="fa fa-check"></i> {{__('Evet')}}
</a>
</div>
</div>
</div>
</div>
<!-- Notification System CSS -->
<style>
.notification-dropdown .notification-badge {
min-width: 18px;
height: 18px;
line-height: 14px;
}
.notification-menu {
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
.notification-list {
max-height: 400px;
overflow-y: auto;
}
.notification-item {
display: flex;
align-items: flex-start;
padding: 14px 18px;
border-bottom: 1px solid rgba(17, 25, 40, 0.08);
cursor: pointer;
position: relative;
background: #ffffff;
transition: background 0.2s ease, box-shadow 0.2s ease;
}
.notification-item:hover {
background: #e8f1ff;
}
.notification-item.unread {
background: #eef6ff;
}
.notification-item.unread::after {
content: '';
width: 8px;
height: 8px;
border-radius: 50%;
background: #3a7bd5;
position: absolute;
top: 18px;
right: 18px;
box-shadow: 0 0 0 2px rgba(58, 123, 213, 0.15);
}
.notification-item:last-child {
border-bottom: none;
}
.notification-item .icon {
width: 36px;
height: 36px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
background: rgba(58, 123, 213, 0.1);
color: #3a7bd5;
margin-right: 12px;
font-size: 16px;
flex-shrink: 0;
}
.notification-item .icon i {
line-height: 1;
}
.notification-item .content {
flex: 1;
min-width: 0;
}
.notification-item .content .title {
font-size: 14px;
font-weight: 600;
color: #111928;
margin-bottom: 4px;
}
.notification-item .content .message {
font-size: 13px;
color: #4a5568;
margin-bottom: 6px;
line-height: 1.4;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.notification-item .content .meta {
font-size: 12px;
color: #6c757d;
display: flex;
align-items: center;
gap: 6px;
}
.notification-item .content .meta i {
font-size: 11px;
opacity: 0.6;
}
.notification-empty {
padding: 48px 24px;
text-align: center;
color: #6c757d;
}
.notification-empty i {
font-size: 36px;
margin-bottom: 12px;
color: rgba(58, 123, 213, 0.55);
}
</style>
<!-- Notification System JavaScript -->
<script>
// Performance: Debounce function to limit API calls
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// Performance: Cache for notification count to avoid repeated API calls
let notificationCountCache = null;
let notificationCountCacheTime = 0;
const CACHE_DURATION = 30000; // 30 seconds
// Load notifications for dropdown
function loadNotifications() {
$.ajax({
url: '/api/notifications/recent',
method: 'GET',
success: function(response) {
displayNotifications(response.notifications);
updateNotificationCount(response.unread_count);
},
error: function() {
$('#notification-list').html(`
<li class="notification-placeholder">
<i class="fa fa-exclamation-triangle text-danger"></i>
<div class="font-weight-bold">{{e2("Unable to load notifications")}}</div>
<div class="small">{{e2("Please try again shortly")}}</div>
</li>
`);
$('#notification-unread-indicator').text('{{e2("Error")}}');
}
});
}
function getNotificationIcon(notificationCode, isRead) {
if (!isRead) {
return 'fa-bell';
}
if (!notificationCode) return 'fa-bell';
const code = notificationCode.toLowerCase();
if (code.includes('success') || code.includes('complete') || code.includes('created')) return 'fa-check-circle';
if (code.includes('error') || code.includes('fail')) return 'fa-exclamation-circle';
if (code.includes('warning') || code.includes('alert')) return 'fa-exclamation-triangle';
if (code.includes('info') || code.includes('update')) return 'fa-info-circle';
if (code.includes('test') || code.includes('inspection')) return 'fa-clipboard-check';
if (code.includes('document') || code.includes('file')) return 'fa-file-alt';
if (code.includes('user') || code.includes('account')) return 'fa-user';
if (code.includes('system') || code.includes('maintenance')) return 'fa-cog';
return 'fa-bell';
}
// Display notifications in dropdown
function displayNotifications(notifications) {
const listContainer = $('#notification-list');
const defaultTitle = '{{e2("Notification")}}';
const defaultMessage = '{{e2("No additional details")}}';
if (!notifications || notifications.length === 0) {
listContainer.html(`
<li class="notification-placeholder">
<i class="fa fa-bell-slash"></i>
<div class="font-weight-bold">{{e2("No notifications")}}</div>
<div class="small">{{e2("You are all caught up")}}</div>
</li>
`);
return;
}
let html = '';
notifications.forEach(function(notif) {
const isUnread = !notif.is_read;
const unreadClass = isUnread ? 'unread' : '';
const timeAgo = formatTimeAgo(notif.created_at);
const link = notif.link || '#';
const safeTitle = notif.title ? escapeHtml(notif.title) : defaultTitle;
const safeMessage = notif.message ? escapeHtml(notif.message) : defaultMessage;
const iconClass = getNotificationIcon(notif.notification_code, !isUnread);
const truncatedMessage = safeMessage.length > 100
? safeMessage.substring(0, 100) + '...'
: safeMessage;
html += `
<li class="notification-item ${unreadClass}"
data-id="${notif.id}"
onclick="handleNotificationClick(${notif.id}, '${escapeHtml(link)}')"
title="${safeMessage}">
<div class="icon">
<i class="fa ${iconClass}"></i>
</div>
<div class="content">
<div class="title">${safeTitle}</div>
<div class="message">${truncatedMessage}</div>
<div class="meta">
<i class="fa fa-clock"></i>
${timeAgo}
</div>
</div>
</li>
`;
});
listContainer.html(html);
}
// Handle notification click
function handleNotificationClick(notificationId, link) {
// Mark as read and wait for response before navigation
$.ajax({
url: '/api/notifications/mark-read/' + notificationId,
method: 'POST',
data: { _token: '{{ csrf_token() }}' },
async: false, // Wait for mark-read to complete
success: function(response) {
if (response.success) {
updateNotificationCount(response.unread_count);
$('[data-id="' + notificationId + '"]').removeClass('unread');
}
}
});
// Navigate to link if provided
if (link && link !== '#') {
window.location.href = link;
}
}
// Mark all notifications as read
function markAllAsRead() {
$.ajax({
url: '/api/notifications/mark-all-read',
method: 'POST',
data: { _token: '{{ csrf_token() }}' },
success: function(response) {
if (response.success) {
updateNotificationCount(0);
$('.notification-item').removeClass('unread');
Swal.fire({
icon: 'success',
title: '{{e2("Success")}}',
text: '{{e2("All notifications marked as read")}}',
timer: 2000,
showConfirmButton: false
});
}
}
});
}
// Update notification count badge
function updateNotificationCount(count) {
notificationCountCache = count;
notificationCountCacheTime = Date.now();
const badge = $('#notification-count');
const indicator = $('#notification-unread-indicator');
if (count > 0) {
const displayCount = count > 99 ? '99+' : count;
badge.text(displayCount).show();
if (indicator.length) {
indicator.text(`${displayCount} {{e2("new")}}`).removeClass('badge-secondary').addClass('badge-primary');
}
} else {
badge.hide();
if (indicator.length) {
indicator.text('{{e2("All caught up")}}').removeClass('badge-primary').addClass('badge-success');
}
}
}
// Fetch notification count (with caching)
function fetchNotificationCount() {
// Use cache if valid
if (notificationCountCache !== null &&
(Date.now() - notificationCountCacheTime) < CACHE_DURATION) {
updateNotificationCount(notificationCountCache);
return;
}
// Performance: Only fetch count, not full notifications
$.ajax({
url: '/api/notifications/unread-count',
method: 'GET',
success: function(response) {
updateNotificationCount(response.unread_count);
}
});
}
// Format time ago
function formatTimeAgo(dateString) {
const date = new Date(dateString);
const now = new Date();
const seconds = Math.floor((now - date) / 1000);
if (seconds < 60) return '{{e2("Just now")}}';
if (seconds < 3600) return Math.floor(seconds / 60) + ' {{e2("min ago")}}';
if (seconds < 86400) return Math.floor(seconds / 3600) + ' {{e2("h ago")}}';
if (seconds < 604800) return Math.floor(seconds / 86400) + ' {{e2("d ago")}}';
return date.toLocaleDateString();
}
// Escape HTML to prevent XSS
function escapeHtml(text) {
const map = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#039;'
};
return text.replace(/[&<>"']/g, function(m) { return map[m]; });
}
// Initialize notification system on page load
$(document).ready(function() {
// Fetch initial count
fetchNotificationCount();
// Poll for new notifications every 15 seconds (for testing - can be increased to 60s in production)
setInterval(fetchNotificationCount, 15000);
// Prevent dropdown from closing when clicking inside
$('.notification-menu').on('click', function(e) {
e.stopPropagation();
});
});
</script>
<div id="screenshotOverlay" style="
display:none;
position:fixed;
inset:0;
background:rgba(0,0,0,.7);
z-index:9999;
padding:20px;
overflow:auto;">
<div style="background:#fff; padding:10px; max-width:90%; margin:0 auto;">
<h5 style="margin-bottom:10px">Crop your screenshot</h5>
<div id="overlayPreview"></div>
<button id="useCropped" class="btn btn-sm btn-primary mt-2">Use this & open feedback</button>
<button id="cancelCrop" class="btn btn-sm btn-secondary mt-2">Cancel</button>
</div>
</div>
</body>
</html>
<style type="text/css">
.cke_button__easyimageupload {
display:none !important;
}
</style>