Files
animexe/resources/views/admin/activation-codes/index.blade.php
T
2026-07-14 00:01:48 +03:00

357 lines
17 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@extends('admin.layouts.app')
@section('title', 'Aktivasyon Kodları')
@section('page-title', 'Aktivasyon Kodları')
@section('content')
{{-- İstatistik kartları --}}
<div class="row g-3 mb-4">
<div class="col-sm-4">
<div class="card h-100 border-0" style="background:rgba(0,245,255,.06);border:1px solid rgba(0,245,255,.18)!important;border-radius:14px">
<div class="card-body text-center py-3">
<div style="font-size:2rem;font-weight:900;color:#00f5ff">{{ number_format($stats['total']) }}</div>
<div style="font-size:.75rem;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.08em">Toplam Kod</div>
</div>
</div>
</div>
<div class="col-sm-4">
<div class="card h-100 border-0" style="background:rgba(50,220,100,.06);border:1px solid rgba(50,220,100,.18)!important;border-radius:14px">
<div class="card-body text-center py-3">
<div style="font-size:2rem;font-weight:900;color:#32dc64">{{ number_format($stats['used']) }}</div>
<div style="font-size:.75rem;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.08em">Kullanılmış</div>
</div>
</div>
</div>
<div class="col-sm-4">
<div class="card h-100 border-0" style="background:rgba(255,214,10,.06);border:1px solid rgba(255,214,10,.18)!important;border-radius:14px">
<div class="card-body text-center py-3">
<div style="font-size:2rem;font-weight:900;color:#ffd60a">{{ number_format($stats['unused']) }}</div>
<div style="font-size:.75rem;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.08em">Kullanılmamış</div>
</div>
</div>
</div>
</div>
{{-- Kod Oluşturma Formu --}}
<div class="card mb-4" style="border-radius:16px;border:1px solid rgba(0,245,255,.15)">
<div class="card-body p-4">
<h6 style="font-weight:800;font-size:.95rem;margin-bottom:20px;display:flex;align-items:center;gap:8px">
<i class="bi bi-plus-circle-fill" style="color:#00f5ff"></i> Yeni Aktivasyon Kodu Oluştur
</h6>
<form method="POST" action="{{ route('admin.activation-codes.generate') }}" id="gen-form">
@csrf
<div class="row g-3">
<div class="col-sm-3">
<label class="form-label" style="font-size:.78rem;font-weight:700">Plan <span class="text-danger">*</span></label>
<select name="plan_id" class="form-select" required>
<option value=""> Plan Seç </option>
@foreach($plans as $plan)
<option value="{{ $plan->id }}" {{ old('plan_id') == $plan->id ? 'selected' : '' }}>
{{ $plan->name }} ({{ $plan->duration_days }} gün)
</option>
@endforeach
</select>
</div>
<div class="col-sm-2">
<label class="form-label" style="font-size:.78rem;font-weight:700">Adet <span class="text-danger">*</span></label>
<input type="number" name="quantity" class="form-control" min="1" max="500" value="{{ old('quantity', 1) }}" required>
</div>
<div class="col-sm-2">
<label class="form-label" style="font-size:.78rem;font-weight:700">Son Kullanma</label>
<input type="date" name="expires_at" class="form-control" value="{{ old('expires_at') }}">
<div class="form-text">Boş = süresiz</div>
</div>
<div class="col-sm-3">
<label class="form-label" style="font-size:.78rem;font-weight:700">Batch Adı</label>
<input type="text" name="batch" class="form-control" placeholder="örn: haziran-2026" value="{{ old('batch') }}" maxlength="64">
<div class="form-text">Grubu tanımlamak için</div>
</div>
<div class="col-sm-2 d-flex align-items-end">
<button type="submit" class="btn w-100" style="background:linear-gradient(135deg,#00f5ff,#b84dff);color:#06060d;font-weight:800;border:none;border-radius:10px;padding:10px">
<i class="bi bi-lightning-fill me-1"></i> Oluştur
</button>
</div>
<div class="col-12">
<label class="form-label" style="font-size:.78rem;font-weight:700">Not (isteğe bağlı)</label>
<input type="text" name="notes" class="form-control" placeholder="İç not..." value="{{ old('notes') }}" maxlength="500">
</div>
</div>
</form>
</div>
</div>
{{-- Oluşturulan kodlar (anlık göster) --}}
@if(session('generated_codes'))
<div class="card mb-4" style="border-radius:16px;border:1px solid rgba(50,220,100,.25);background:rgba(50,220,100,.04)">
<div class="card-body p-4">
<div class="d-flex align-items-center justify-content-between mb-3">
<h6 style="font-weight:800;font-size:.95rem;margin:0;color:#32dc64">
<i class="bi bi-check-circle-fill me-2"></i>{{ count(session('generated_codes')) }} Kod Oluşturuldu
</h6>
<div class="d-flex gap-2">
<button onclick="copyAllCodes(this)" class="btn btn-sm" style="border:1px solid rgba(0,245,255,.3);color:#00f5ff;background:rgba(0,245,255,.06);border-radius:8px;font-size:.78rem;font-weight:700">
<i class="bi bi-clipboard me-1"></i> Tümünü Kopyala
</button>
</div>
</div>
<div id="generated-codes-list" style="display:flex;flex-wrap:wrap;gap:8px">
@foreach(session('generated_codes') as $gc)
<span class="generated-code" style="font-family:monospace;font-size:.88rem;font-weight:700;color:#e0f7ff;padding:6px 14px;background:rgba(0,245,255,.08);border:1px solid rgba(0,245,255,.2);border-radius:8px;cursor:pointer;letter-spacing:.08em;transition:all .15s"
onclick="navigator.clipboard.writeText('{{ $gc }}').then(()=>{ this.style.borderColor='#32dc64';this.style.color='#32dc64'; setTimeout(()=>{ this.style.borderColor='rgba(0,245,255,.2)';this.style.color='#e0f7ff'; },1500); })"
title="Kopyalamak için tıkla">{{ $gc }}</span>
@endforeach
</div>
</div>
</div>
@endif
@if(session('success'))
<div class="alert alert-success d-flex align-items-center gap-2" style="border-radius:12px;font-size:.85rem">
<i class="bi bi-check-circle-fill"></i> {{ session('success') }}
</div>
@endif
{{-- Filtreler --}}
<div class="filter-card mb-3">
<form method="GET" class="d-flex flex-wrap gap-2 align-items-end">
<div class="flex-grow-1" style="min-width:160px;max-width:220px">
<label class="form-label mb-1" style="font-size:.75rem;font-weight:700">Plan</label>
<select name="plan_id" class="form-select form-select-sm">
<option value="">Tüm Planlar</option>
@foreach($plans as $plan)
<option value="{{ $plan->id }}" {{ request('plan_id') == $plan->id ? 'selected' : '' }}>{{ $plan->name }}</option>
@endforeach
</select>
</div>
<div style="min-width:140px">
<label class="form-label mb-1" style="font-size:.75rem;font-weight:700">Durum</label>
<select name="status" class="form-select form-select-sm">
<option value="">Tümü</option>
<option value="unused" {{ request('status') === 'unused' ? 'selected' : '' }}>Kullanılmamış</option>
<option value="used" {{ request('status') === 'used' ? 'selected' : '' }}>Kullanılmış</option>
</select>
</div>
@if($batches->isNotEmpty())
<div style="min-width:160px">
<label class="form-label mb-1" style="font-size:.75rem;font-weight:700">Batch</label>
<select name="batch" class="form-select form-select-sm">
<option value="">Tüm Batch'ler</option>
@foreach($batches as $b)
<option value="{{ $b }}" {{ request('batch') === $b ? 'selected' : '' }}>{{ $b }}</option>
@endforeach
</select>
</div>
@endif
<div class="d-flex gap-2">
<button type="submit" class="btn btn-sm btn-primary" style="border-radius:8px;font-weight:700">Filtrele</button>
<a href="{{ route('admin.activation-codes.index') }}" class="btn btn-sm btn-outline-secondary" style="border-radius:8px">Temizle</a>
<a href="{{ route('admin.activation-codes.export') }}?{{ http_build_query(request()->only('plan_id','batch')) }}"
class="btn btn-sm" style="border:1px solid rgba(0,245,255,.3);color:#00f5ff;background:rgba(0,245,255,.06);border-radius:8px;font-weight:700">
<i class="bi bi-download me-1"></i>CSV
</a>
</div>
</form>
</div>
{{-- Batch toplu silme --}}
@if(request('batch'))
<div class="d-flex justify-content-end mb-2">
<form method="POST" action="{{ route('admin.activation-codes.destroy-batch') }}" onsubmit="return confirm('Bu batch\'teki kullanılmamış kodların tümü silinecek. Emin misiniz?')">
@csrf
<input type="hidden" name="batch" value="{{ request('batch') }}">
<button type="submit" class="btn btn-sm btn-danger" style="border-radius:8px;font-size:.78rem;font-weight:700">
<i class="bi bi-trash me-1"></i> "{{ request('batch') }}" Batch — Kullanılmamışları Sil
</button>
</form>
</div>
@endif
{{-- Toplu seçim aksiyonu --}}
<div id="bulk-bar" style="display:none;align-items:center;gap:12px;padding:10px 16px;margin-bottom:12px;background:rgba(255,80,80,.07);border:1px solid rgba(255,80,80,.25);border-radius:12px">
<span style="font-size:.85rem;font-weight:700;color:#ff8080">
<i class="bi bi-check2-square me-1"></i>
<span id="sel-count">0</span> kod seçildi
</span>
<button onclick="bulkDelete()" class="btn btn-sm btn-danger" style="border-radius:8px;font-size:.78rem;font-weight:700;padding:5px 14px">
<i class="bi bi-trash3 me-1"></i> Seçilenleri Sil
</button>
<button onclick="clearSelection()" class="btn btn-sm btn-outline-secondary" style="border-radius:8px;font-size:.78rem">
İptal
</button>
</div>
{{-- Gizli bulk delete formu --}}
<form id="bulk-del-form" method="POST" action="{{ route('admin.activation-codes.destroy-selected') }}" style="display:none">
@csrf
</form>
{{-- Tablo --}}
<div class="card" style="border-radius:16px;overflow:hidden">
<div class="table-responsive">
<table class="table table-hover mb-0" style="font-size:.84rem">
<thead style="border-bottom:1px solid rgba(255,255,255,.08)">
<tr>
<th style="padding:12px 16px;width:44px">
<input type="checkbox" id="select-all" class="form-check-input" style="width:16px;height:16px;cursor:pointer;background:rgba(255,255,255,.06);border-color:rgba(255,255,255,.3)">
</th>
<th style="font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;padding:12px 16px">Kod</th>
<th style="font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em">Plan</th>
<th style="font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em">Batch</th>
<th style="font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em">Durum</th>
<th style="font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em">Kullanan</th>
<th style="font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em">Son Kullanma</th>
<th style="font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em">Oluşturulma</th>
<th style="width:60px"></th>
</tr>
</thead>
<tbody>
@forelse($codes as $code)
<tr>
<td style="padding:11px 16px">
@if(!$code->isUsed())
<input type="checkbox" class="row-check form-check-input" value="{{ $code->id }}"
style="width:16px;height:16px;cursor:pointer;background:rgba(255,255,255,.06);border-color:rgba(255,255,255,.3)">
@endif
</td>
<td style="padding:11px 16px">
<code style="font-size:.88rem;font-weight:700;letter-spacing:.1em;color:#00f5ff;cursor:pointer"
onclick="navigator.clipboard.writeText('{{ $code->code }}').then(()=>showToast?.('Kopyalandı'))"
title="Kopyalamak için tıkla">{{ $code->code }}</code>
</td>
<td>
<span style="font-size:.78rem;font-weight:700;padding:3px 10px;border-radius:8px;background:rgba(0,245,255,.08);color:#00f5ff">
{{ $code->plan->name ?? '—' }}
</span>
</td>
<td style="color:rgba(255,255,255,.4);font-size:.78rem">{{ $code->batch ?? '—' }}</td>
<td>
@if($code->isUsed())
<span style="display:inline-flex;align-items:center;gap:4px;font-size:.75rem;font-weight:700;padding:3px 10px;border-radius:8px;background:rgba(50,220,100,.1);color:#32dc64;border:1px solid rgba(50,220,100,.2)">
<i class="bi bi-check-circle-fill"></i> Kullanıldı
</span>
@elseif($code->isExpired())
<span style="display:inline-flex;align-items:center;gap:4px;font-size:.75rem;font-weight:700;padding:3px 10px;border-radius:8px;background:rgba(255,80,80,.08);color:#ff5050;border:1px solid rgba(255,80,80,.2)">
<i class="bi bi-clock-history"></i> Süresi Doldu
</span>
@else
<span style="display:inline-flex;align-items:center;gap:4px;font-size:.75rem;font-weight:700;padding:3px 10px;border-radius:8px;background:rgba(255,214,10,.08);color:#ffd60a;border:1px solid rgba(255,214,10,.2)">
<i class="bi bi-hourglass-split"></i> Bekliyor
</span>
@endif
</td>
<td>
@if($code->usedBy)
<span style="font-size:.8rem;color:rgba(255,255,255,.65)">{{ $code->usedBy->name }}</span>
<div style="font-size:.7rem;color:rgba(255,255,255,.3)">{{ $code->used_at?->format('d.m.Y H:i') }}</div>
@else
<span style="color:rgba(255,255,255,.2);font-size:.78rem"></span>
@endif
</td>
<td style="font-size:.78rem;color:rgba(255,255,255,.4)">
{{ $code->expires_at?->format('d.m.Y') ?? '∞ Süresiz' }}
</td>
<td style="font-size:.78rem;color:rgba(255,255,255,.35)">
{{ $code->created_at->format('d.m.Y') }}
</td>
<td>
@if(!$code->isUsed())
<form method="POST" action="{{ route('admin.activation-codes.destroy', $code) }}"
onsubmit="return confirm('Bu kodu silmek istediğine emin misin?')">
@csrf @method('DELETE')
<button type="submit" class="btn btn-sm" style="color:rgba(255,80,80,.6);background:none;border:none;padding:6px 8px;border-radius:7px;transition:all .15s"
onmouseover="this.style.background='rgba(255,80,80,.1)';this.style.color='#ff5050'"
onmouseout="this.style.background='none';this.style.color='rgba(255,80,80,.6)'"
title="Sil">
<i class="bi bi-trash3"></i>
</button>
</form>
@endif
</td>
</tr>
@empty
<tr>
<td colspan="9" class="text-center py-5" style="color:rgba(255,255,255,.3)">
<i class="bi bi-key" style="font-size:2rem;display:block;margin-bottom:10px;opacity:.3"></i>
Henüz aktivasyon kodu yok. Yukarıdan oluşturabilirsin.
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
{{-- Pagination --}}
@if($codes->hasPages())
<div class="mt-3">{{ $codes->links() }}</div>
@endif
<script>
(function () {
const selectAll = document.getElementById('select-all');
const bulkBar = document.getElementById('bulk-bar');
const selCount = document.getElementById('sel-count');
function getChecked() {
return [...document.querySelectorAll('.row-check:checked')];
}
function updateBulkBar() {
const n = getChecked().length;
bulkBar.style.display = n > 0 ? 'flex' : 'none';
selCount.textContent = n;
const all = document.querySelectorAll('.row-check');
selectAll.indeterminate = n > 0 && n < all.length;
selectAll.checked = all.length > 0 && n === all.length;
}
selectAll.addEventListener('change', function () {
document.querySelectorAll('.row-check').forEach(cb => cb.checked = this.checked);
updateBulkBar();
});
document.querySelectorAll('.row-check').forEach(cb => {
cb.addEventListener('change', updateBulkBar);
});
window.clearSelection = function () {
document.querySelectorAll('.row-check').forEach(cb => cb.checked = false);
selectAll.checked = false;
updateBulkBar();
};
window.bulkDelete = function () {
const checked = getChecked();
if (!checked.length) return;
if (!confirm(checked.length + ' adet kodu silmek istediğine emin misin? Bu işlem geri alınamaz.')) return;
const form = document.getElementById('bulk-del-form');
form.querySelectorAll('input[name="ids[]"]').forEach(el => el.remove());
checked.forEach(cb => {
const inp = document.createElement('input');
inp.type = 'hidden';
inp.name = 'ids[]';
inp.value = cb.value;
form.appendChild(inp);
});
form.submit();
};
})();
function copyAllCodes(btn) {
const codes = [...document.querySelectorAll('.generated-code')].map(el => el.textContent.trim());
if (!codes.length) return;
navigator.clipboard.writeText(codes.join('\n')).then(() => {
btn.innerHTML = '<i class="bi bi-check-lg me-1"></i> Kopyalandı!';
btn.style.color = '#32dc64';
btn.style.borderColor = 'rgba(50,220,100,.4)';
setTimeout(() => {
btn.innerHTML = '<i class="bi bi-clipboard me-1"></i> Tümünü Kopyala';
btn.style.color = '#00f5ff';
btn.style.borderColor = 'rgba(0,245,255,.3)';
}, 2000);
});
}
</script>
@endsection