2 Commits

3 changed files with 277 additions and 78 deletions
+11
View File
@@ -494,6 +494,8 @@ class CareerController extends Controller
], [ ], [
'content' => $request->content, 'content' => $request->content,
'is_retroactive' => $isRetroactive, 'is_retroactive' => $isRetroactive,
'supervisor_approved' => false,
'supervisor_name' => null,
]); ]);
return response()->json([ return response()->json([
@@ -521,6 +523,15 @@ class CareerController extends Controller
} }
$days = self::getInternshipDates($intern->internship_start_date, $intern->internship_total_days); $days = self::getInternshipDates($intern->internship_start_date, $intern->internship_total_days);
$dayFilter = $request->query('day');
if ($dayFilter) {
$days = array_filter($days, function($d) use ($dayFilter) {
return $d['day_number'] == $dayFilter;
});
$days = array_values($days);
}
$savedEntries = $intern->journalEntries()->get()->keyBy('day_number'); $savedEntries = $intern->journalEntries()->get()->keyBy('day_number');
return view('front.career.print', [ return view('front.career.print', [
@@ -684,6 +684,7 @@
$dayDate = $d['date']; $dayDate = $d['date'];
$dayDateFormatted = $d['formatted_date']; $dayDateFormatted = $d['formatted_date'];
$hasSaved = isset($savedEntries[$dayNum]) && trim($savedEntries[$dayNum]->content) !== ''; $hasSaved = isset($savedEntries[$dayNum]) && trim($savedEntries[$dayNum]->content) !== '';
$isApproved = isset($savedEntries[$dayNum]) && $savedEntries[$dayNum]->supervisor_approved;
@endphp @endphp
<button type="button" <button type="button"
onclick="selectNotebookDay({{ $idx }})" onclick="selectNotebookDay({{ $idx }})"
@@ -692,13 +693,19 @@
data-date="{{ $dayDate }}" data-date="{{ $dayDate }}"
data-formatted-date="{{ $dayDateFormatted }}" data-formatted-date="{{ $dayDateFormatted }}"
data-saved-content="{{ $savedEntries[$dayNum]->content ?? '' }}" data-saved-content="{{ $savedEntries[$dayNum]->content ?? '' }}"
data-approved="{{ $isApproved ? '1' : '0' }}"
class="notebook-day-btn w-full flex items-center justify-between p-3 rounded-2xl border text-left transition-all @if($idx === 0) border-blue-200 bg-blue-50/50 @else border-slate-100 bg-white hover:bg-slate-50 @endif"> class="notebook-day-btn w-full flex items-center justify-between p-3 rounded-2xl border text-left transition-all @if($idx === 0) border-blue-200 bg-blue-50/50 @else border-slate-100 bg-white hover:bg-slate-50 @endif">
<div> <div>
<span class="block text-xs font-extrabold @if($idx === 0) text-blue-700 @else text-slate-800 @endif">{{ $dayNum }}. Gün</span> <span class="block text-xs font-extrabold @if($idx === 0) text-blue-700 @else text-slate-800 @endif">{{ $dayNum }}. Gün</span>
<span class="block text-[10px] text-slate-400 mt-0.5">{{ $dayDateFormatted }}</span> <span class="block text-[10px] text-slate-400 mt-0.5">{{ $dayDateFormatted }}</span>
</div> </div>
<span id="badge-day-{{ $idx }}" class="inline-flex px-2 py-0.5 rounded-lg text-[9px] font-extrabold uppercase @if($hasSaved) bg-green-50 text-green-700 border border-green-200 @else bg-slate-50 text-slate-400 border border-slate-200 @endif"> <span id="badge-day-{{ $idx }}" class="inline-flex px-2 py-0.5 rounded-lg text-[9px] font-extrabold uppercase
{{ $hasSaved ? 'DOLU' : 'BOŞ' }} @if($isApproved) bg-green-500 text-white border border-green-600
@elseif($hasSaved) bg-amber-50 text-amber-700 border border-amber-200
@else bg-slate-50 text-slate-400 border border-slate-200 @endif">
@if($isApproved) ONAYLANDI
@elseif($hasSaved) DOLU
@else BOŞ @endif
</span> </span>
</button> </button>
@endforeach @endforeach
@@ -708,17 +715,25 @@
<div class="lg:col-span-8 space-y-4"> <div class="lg:col-span-8 space-y-4">
<div class="bg-white border border-slate-100 rounded-2xl p-5 shadow-sm"> <div class="bg-white border border-slate-100 rounded-2xl p-5 shadow-sm">
<div class="flex items-center justify-between pb-3 border-b border-slate-100 mb-4"> <div class="flex items-center justify-between pb-3 border-b border-slate-100 mb-4">
<div> <div class="flex items-center">
<span id="editor-day-title" class="text-sm font-extrabold text-blue-600 bg-blue-50 px-3 py-1 rounded-full">1. Gün</span> <span id="editor-day-title" class="text-sm font-extrabold text-blue-600 bg-blue-50 px-3 py-1 rounded-full">1. Gün</span>
<span id="editor-day-date" class="text-xs font-semibold text-slate-400 ml-2"></span> <span id="editor-day-date" class="text-xs font-semibold text-slate-400 ml-2"></span>
<span id="editor-day-status" class="ml-2"></span>
</div> </div>
@if($intern->github_repo) <div class="flex items-center gap-2">
<button type="button" onclick="fillFromGithub()" class="px-3 py-1.5 bg-slate-800 hover:bg-slate-900 text-white font-extrabold rounded-lg text-[10px] transition-all flex items-center gap-1.5 shadow-sm"> @if($intern->github_repo)
<i class="uil uil-github text-xs"></i> <button type="button" onclick="fillFromGithub()" class="px-3 py-1.5 bg-slate-800 hover:bg-slate-900 text-white font-extrabold rounded-lg text-[10px] transition-all flex items-center gap-1.5 shadow-sm">
<span>Git Commitlerini Çek</span> <i class="uil uil-github text-xs"></i>
</button> <span>Git Commitlerini Çek</span>
@endif </button>
@endif
<button type="button" onclick="printActiveDay()" class="px-3 py-1.5 bg-green-600 hover:bg-green-700 text-white font-extrabold rounded-lg text-[10px] transition-all flex items-center gap-1.5 shadow-sm">
<i class="uil uil-print text-xs"></i>
<span>Yazdır</span>
</button>
</div>
</div> </div>
<div class="space-y-4"> <div class="space-y-4">
@@ -733,6 +748,19 @@
</div> </div>
</div> </div>
<div id="git-commits-fallback-container" class="hidden p-4 bg-slate-50 border border-slate-200/60 rounded-2xl text-xs space-y-3">
<div class="flex justify-between items-center pb-2 border-b border-slate-200">
<span class="font-extrabold text-slate-700 flex items-center gap-1.5">
<i class="uil uil-info-circle text-blue-600 text-sm"></i>
<span>Seçilen güne ait otomatik commit bulunamadı. Son 10 commit'iniz:</span>
</span>
<button type="button" onclick="hideFallbackCommits()" class="text-slate-400 hover:text-slate-600 font-extrabold">Kapat</button>
</div>
<div id="git-commits-fallback-list" class="space-y-2 max-h-[150px] overflow-y-auto pr-1 no-scrollbar">
<!-- items dynamically populated -->
</div>
</div>
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<div id="save-status" class="text-xs font-semibold text-slate-400"></div> <div id="save-status" class="text-xs font-semibold text-slate-400"></div>
<button type="button" id="save-btn" onclick="saveActiveDay()" class="px-5 py-2.5 bg-blue-600 hover:bg-blue-700 text-white font-bold rounded-xl text-xs transition-all shadow-md shadow-blue-500/10"> <button type="button" id="save-btn" onclick="saveActiveDay()" class="px-5 py-2.5 bg-blue-600 hover:bg-blue-700 text-white font-bold rounded-xl text-xs transition-all shadow-md shadow-blue-500/10">
@@ -855,56 +883,78 @@
// Handle initial state of date logic // Handle initial state of date logic
calculateEndDateFrontend(); calculateEndDateFrontend();
// Fetch Github commits in memory if repo is set
fetchAllCommitsInMemory();
// Select first day of the notebook workspace on load // Select first day of the notebook workspace on load
selectNotebookDay(0); selectNotebookDay(0);
}); });
const githubRepoUrl = @json($intern->github_repo); const githubRepoUrl = @json($intern->github_repo);
let allGithubCommits = {};
let activeDayIdx = 0; let activeDayIdx = 0;
function fetchAllCommitsInMemory() { function hideFallbackCommits() {
if (!githubRepoUrl) return; const container = document.getElementById('git-commits-fallback-container');
if (container) {
container.classList.add('hidden');
}
}
let repoClean = githubRepoUrl.replace(/https?:\/\/(www\.)?github\.com\//i, ''); function formatDateToIstanbul(d) {
repoClean = repoClean.replace(/\/$/, ''); try {
const parts = repoClean.split('/'); const formatter = new Intl.DateTimeFormat('en-US', {
if (parts.length < 2) return; timeZone: 'Europe/Istanbul',
year: 'numeric',
const owner = parts[0]; month: '2-digit',
const repo = parts[1].replace(/\.git$/i, ''); day: '2-digit'
fetch(`https://api.github.com/repos/${owner}/${repo}/commits?per_page=100`)
.then(response => {
if (!response.ok) throw new Error('API Error');
return response.json();
})
.then(commits => {
if (!Array.isArray(commits)) return;
commits.forEach(item => {
const dateStr = item.commit.author.date;
if (dateStr) {
const d = new Date(dateStr);
const formatter = new Intl.DateTimeFormat('fr-CA', {
timeZone: 'Europe/Istanbul',
year: 'numeric',
month: '2-digit',
day: '2-digit'
});
const dateOnly = formatter.format(d);
if (!allGithubCommits[dateOnly]) {
allGithubCommits[dateOnly] = [];
}
allGithubCommits[dateOnly].push(item);
}
});
})
.catch(err => {
console.warn('Commits could not be pre-loaded in memory.', err);
}); });
const parts = formatter.formatToParts(d);
const year = parts.find(p => p.type === 'year').value;
const month = parts.find(p => p.type === 'month').value;
const day = parts.find(p => p.type === 'day').value;
return `${year}-${month}-${day}`;
} catch (e) {
return d.toISOString().split('T')[0];
}
}
function updateEditorStatusBadge(isApproved, hasSaved) {
const statusSpan = document.getElementById('editor-day-status');
if (!statusSpan) return;
if (isApproved) {
statusSpan.textContent = 'ONAYLANDI';
statusSpan.className = 'inline-flex px-2 py-0.5 rounded-full text-[10px] font-extrabold uppercase bg-green-500 text-white border border-green-600 ml-2';
} else if (hasSaved) {
statusSpan.textContent = 'ONAY BEKLİYOR';
statusSpan.className = 'inline-flex px-2 py-0.5 rounded-full text-[10px] font-extrabold uppercase bg-amber-50 text-amber-700 border border-amber-200 ml-2';
} else {
statusSpan.textContent = '';
statusSpan.className = 'hidden';
}
}
function printActiveDay() {
const btn = document.getElementById(`btn-day-${activeDayIdx}`);
if (!btn) return;
const dayNum = btn.getAttribute('data-day-num');
window.open(`{{ route('intern.print-journal') }}?size=a4&day=${dayNum}`, '_blank');
}
function appendCommitToQuill(sha, time, msg) {
const escapedMsg = msg.replace(/</g, "&lt;").replace(/>/g, "&gt;");
const commitHtml = `<li><strong>[${time}]</strong> (<em>${sha}</em>) ${escapedMsg}</li>`;
const currentHtml = quill.root.innerHTML.trim();
const hasHeader = currentHtml.includes("Git Commit Mesajları:");
const headerHtml = hasHeader ? "" : "<p><strong>Git Commit Mesajları:</strong></p>";
let newHtml = "";
if (currentHtml !== "" && currentHtml !== "<p><br></p>") {
newHtml = currentHtml + "<br><br>" + headerHtml + "<ul>" + commitHtml + "</ul>";
} else {
newHtml = headerHtml + "<ul>" + commitHtml + "</ul>";
}
quill.setContents([]);
quill.clipboard.dangerouslyPasteHTML(newHtml);
} }
function selectNotebookDay(idx) { function selectNotebookDay(idx) {
@@ -934,12 +984,20 @@
const dateVal = newBtn.getAttribute('data-date'); const dateVal = newBtn.getAttribute('data-date');
const dateFormatted = newBtn.getAttribute('data-formatted-date'); const dateFormatted = newBtn.getAttribute('data-formatted-date');
const savedContent = newBtn.getAttribute('data-saved-content'); const savedContent = newBtn.getAttribute('data-saved-content');
const isApproved = newBtn.getAttribute('data-approved') === '1';
document.getElementById('editor-day-title').textContent = `${dayNum}. Gün`; document.getElementById('editor-day-title').textContent = `${dayNum}. Gün`;
document.getElementById('editor-day-date').textContent = dateFormatted; document.getElementById('editor-day-date').textContent = dateFormatted;
quill.root.innerHTML = savedContent || ''; quill.setContents([]);
if (savedContent) {
quill.clipboard.dangerouslyPasteHTML(savedContent);
}
document.getElementById('save-status').textContent = ''; document.getElementById('save-status').textContent = '';
hideFallbackCommits();
const hasSaved = savedContent && savedContent.trim() !== '' && savedContent !== '<p><br></p>';
updateEditorStatusBadge(isApproved, hasSaved);
// Future validation // Future validation
const dateParts = dateVal.split('-'); const dateParts = dateVal.split('-');
@@ -979,34 +1037,160 @@
if (!btn) return; if (!btn) return;
const dateVal = btn.getAttribute('data-date'); const dateVal = btn.getAttribute('data-date');
const dayCommits = allGithubCommits[dateVal] || []; const formattedDate = btn.getAttribute('data-formatted-date');
if (dayCommits.length === 0) { if (!githubRepoUrl) {
alert("Bu staj gününe ait GitHub commit'i bulunamadı. Lütfen commit attığınızdan ve tarihin doğru olduğundan emin olun."); alert("Lütfen önce GitHub depo URL'nizi kaydedin.");
return; return;
} }
let commitHtml = "<ul>"; let repoClean = githubRepoUrl.replace(/https?:\/\/(www\.)?github\.com\//i, '');
const sorted = [...dayCommits].reverse(); repoClean = repoClean.replace(/\/$/, '');
sorted.forEach(c => { const parts = repoClean.split('/');
const msg = c.commit.message; if (parts.length < 2) {
const sha = c.sha.substring(0, 7); alert("Geçersiz GitHub URL'si.");
const authorDate = new Date(c.commit.author.date); return;
const time = authorDate.toLocaleTimeString('tr-TR', { timeZone: 'Europe/Istanbul', hour: '2-digit', minute: '2-digit' });
commitHtml += `<li><strong>[${time}]</strong> (<em>${sha}</em>) ${msg}</li>`;
});
commitHtml += "</ul>";
const currentHtml = quill.root.innerHTML.trim();
if (currentHtml !== "" && currentHtml !== "<p><br></p>") {
if (confirm("Mevcut rapor içeriğinizin sonuna bu günün commitlerini eklemek ister misiniz? (Hayır derseniz mevcut içerik silinip commitler yazılır.)")) {
quill.root.innerHTML = currentHtml + "<br><br>" + commitHtml;
} else {
quill.root.innerHTML = commitHtml;
}
} else {
quill.root.innerHTML = commitHtml;
} }
const owner = parts[0];
const repo = parts[1].replace(/\.git$/i, '');
let branch = '';
// Parse branch if /tree/{branch} or /commits/{branch} is used
if (parts.length >= 4 && (parts[2] === 'tree' || parts[2] === 'commits')) {
branch = parts.slice(3).join('/');
}
const gitBtn = document.querySelector('button[onclick="fillFromGithub()"]');
const originalContent = gitBtn.innerHTML;
gitBtn.disabled = true;
gitBtn.innerHTML = `<i class="uil uil-spinner text-xs animate-spin"></i> <span>Çekiliyor...</span>`;
hideFallbackCommits();
fetch(`https://api.github.com/repos/${owner}/${repo}/commits?per_page=100${branch ? `&sha=${branch}` : ''}`)
.then(response => {
if (!response.ok) {
if (response.status === 404) {
throw new Error("Depo bulunamadı veya herkese açık (public) değil.");
} else if (response.status === 403) {
throw new Error("GitHub API istek limitine ulaşıldı. Lütfen daha sonra tekrar deneyin.");
} else {
throw new Error(`GitHub API Hatası (Kod: ${response.status})`);
}
}
return response.json();
})
.then(commits => {
if (!Array.isArray(commits)) {
throw new Error("Geçersiz API yanıtı.");
}
// Filter commits by the selected date
const dayCommits = commits.filter(item => {
const dateStr = item.commit.author.date;
if (!dateStr) return false;
const d = new Date(dateStr);
const dateOnly = formatDateToIstanbul(d);
return dateOnly === dateVal;
});
if (dayCommits.length === 0) {
// No commits found for this date. Show fallback list of latest 10 commits.
const fallbackContainer = document.getElementById('git-commits-fallback-container');
const fallbackList = document.getElementById('git-commits-fallback-list');
if (fallbackContainer && fallbackList) {
fallbackList.innerHTML = '';
const latestCommits = commits.slice(0, 10);
if (latestCommits.length === 0) {
fallbackList.innerHTML = `<p class="text-slate-400 italic">Depoda hiç commit bulunamadı.</p>`;
} else {
latestCommits.forEach(c => {
const msg = c.commit.message;
const sha = c.sha.substring(0, 7);
const authorDate = new Date(c.commit.author.date);
const time = authorDate.toLocaleTimeString('tr-TR', { timeZone: 'Europe/Istanbul', hour: '2-digit', minute: '2-digit' });
const commitDateOnly = formatDateToIstanbul(authorDate);
// format date to d.m.Y
const [cy, cm, cd] = commitDateOnly.split('-');
const formattedCommitDate = `${cd}.${cm}.${cy}`;
const row = document.createElement('div');
row.className = "flex items-center justify-between gap-3 p-2 hover:bg-slate-100 rounded-lg border border-slate-100 transition-colors";
const infoDiv = document.createElement('div');
infoDiv.className = "flex-grow min-w-0";
const timeSpan = document.createElement('span');
timeSpan.className = "font-bold text-slate-700 select-all";
timeSpan.textContent = `[${formattedCommitDate} ${time}] `;
const shaSpan = document.createElement('span');
shaSpan.className = "text-slate-500 font-semibold select-all";
shaSpan.textContent = `(${sha}) `;
const msgSpan = document.createElement('span');
msgSpan.className = "text-slate-600 truncate block sm:inline-block max-w-full font-medium ml-1";
msgSpan.textContent = msg;
infoDiv.appendChild(timeSpan);
infoDiv.appendChild(shaSpan);
infoDiv.appendChild(msgSpan);
const addBtn = document.createElement('button');
addBtn.type = 'button';
addBtn.className = "px-2 py-1 bg-blue-50 text-blue-600 hover:bg-blue-600 hover:text-white font-extrabold rounded transition-all flex-shrink-0 text-[10px]";
addBtn.textContent = "Ekle";
addBtn.addEventListener('click', () => {
appendCommitToQuill(sha, `${formattedCommitDate} ${time}`, msg);
});
row.appendChild(infoDiv);
row.appendChild(addBtn);
fallbackList.appendChild(row);
});
}
fallbackContainer.classList.remove('hidden');
alert(`Bu staj gününe (${formattedDate}) ait otomatik GitHub commit'i bulunamadı. Son 10 commit'iniz aşağıda listelenmiştir, rapora eklemek istediklerinizi seçebilirsiniz.`);
} else {
alert(`Bu staj gününe (${formattedDate}) ait GitHub commit'i bulunamadı. Lütfen commit attığınızdan ve tarihin doğru olduğundan emin olun.`);
}
return;
}
let commitHtml = "<ul>";
const sorted = [...dayCommits].reverse();
sorted.forEach(c => {
const msg = c.commit.message;
const sha = c.sha.substring(0, 7);
const authorDate = new Date(c.commit.author.date);
const time = authorDate.toLocaleTimeString('tr-TR', { timeZone: 'Europe/Istanbul', hour: '2-digit', minute: '2-digit' });
commitHtml += `<li><strong>[${time}]</strong> (<em>${sha}</em>) ${msg}</li>`;
});
commitHtml += "</ul>";
const currentHtml = quill.root.innerHTML.trim();
const headerHtml = "<p><strong>Git Commit Mesajları:</strong></p>";
let newHtml = "";
if (currentHtml !== "" && currentHtml !== "<p><br></p>") {
newHtml = currentHtml + "<br><br>" + headerHtml + commitHtml;
} else {
newHtml = headerHtml + commitHtml;
}
quill.setContents([]);
quill.clipboard.dangerouslyPasteHTML(newHtml);
})
.catch(err => {
alert("Commitler çekilirken hata oluştu: " + err.message);
})
.finally(() => {
gitBtn.disabled = false;
gitBtn.innerHTML = originalContent;
});
} }
function saveActiveDay() { function saveActiveDay() {
@@ -1043,17 +1227,21 @@
statusText.className = "text-xs font-semibold text-green-600"; statusText.className = "text-xs font-semibold text-green-600";
btn.setAttribute('data-saved-content', contentVal); btn.setAttribute('data-saved-content', contentVal);
btn.setAttribute('data-approved', '0');
const badge = document.getElementById(`badge-day-${activeDayIdx}`); const badge = document.getElementById(`badge-day-${activeDayIdx}`);
const hasContent = contentVal.trim() !== '' && contentVal !== '<p><br></p>';
if (badge) { if (badge) {
if (contentVal.trim() !== '') { if (hasContent) {
badge.textContent = 'DOLU'; badge.textContent = 'DOLU';
badge.className = "inline-flex px-2 py-0.5 rounded-lg text-[9px] font-extrabold uppercase bg-green-50 text-green-700 border border-green-200"; badge.className = "inline-flex px-2 py-0.5 rounded-lg text-[9px] font-extrabold uppercase bg-amber-50 text-amber-700 border border-amber-200";
} else { } else {
badge.textContent = 'BOŞ'; badge.textContent = 'BOŞ';
badge.className = "inline-flex px-2 py-0.5 rounded-lg text-[9px] font-extrabold uppercase bg-slate-50 text-slate-400 border border-slate-200"; badge.className = "inline-flex px-2 py-0.5 rounded-lg text-[9px] font-extrabold uppercase bg-slate-50 text-slate-400 border border-slate-200";
} }
} }
updateEditorStatusBadge(false, hasContent);
} else { } else {
statusText.textContent = data.message || "Kaydedilemedi."; statusText.textContent = data.message || "Kaydedilemedi.";
statusText.className = "text-xs font-semibold text-red-600"; statusText.className = "text-xs font-semibold text-red-600";
+2 -2
View File
@@ -331,8 +331,8 @@
<span>Panele Dön</span> <span>Panele Dön</span>
</a> </a>
<div style="border-left: 1px solid #e2e8f0; margin: 0 5px; height: 35px;"></div> <div style="border-left: 1px solid #e2e8f0; margin: 0 5px; height: 35px;"></div>
<a href="?size=a4{{ request()->has('intern_id') ? '&intern_id='.request('intern_id') : '' }}" class="btn {{ $size === 'a4' ? 'btn-primary' : 'btn-secondary' }}">A4 Boyutu</a> <a href="?size=a4{{ request()->has('intern_id') ? '&intern_id='.request('intern_id') : '' }}{{ request()->has('day') ? '&day='.request('day') : '' }}" class="btn {{ $size === 'a4' ? 'btn-primary' : 'btn-secondary' }}">A4 Boyutu</a>
<a href="?size=a5{{ request()->has('intern_id') ? '&intern_id='.request('intern_id') : '' }}" class="btn {{ $size === 'a5' ? 'btn-primary' : 'btn-secondary' }}">A5 Boyutu</a> <a href="?size=a5{{ request()->has('intern_id') ? '&intern_id='.request('intern_id') : '' }}{{ request()->has('day') ? '&day='.request('day') : '' }}" class="btn {{ $size === 'a5' ? 'btn-primary' : 'btn-secondary' }}">A5 Boyutu</a>
<button onclick="window.print()" class="btn btn-primary"> <button onclick="window.print()" class="btn btn-primary">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 6 2 18 2 18 9"/><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"/><rect x="6" y="14" width="12" height="8"/></svg> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 6 2 18 2 18 9"/><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"/><rect x="6" y="14" width="12" height="8"/></svg>
<span>Yazdır / PDF Kaydet</span> <span>Yazdır / PDF Kaydet</span>