Initial commit: Animexe Laravel platform

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 00:01:48 +03:00
co-authored by Claude Opus 4.8
commit a63515cfc6
366 changed files with 74773 additions and 0 deletions
+117
View File
@@ -0,0 +1,117 @@
@extends('admin.layouts.app')
@section('title', 'Reklam Düzenle')
@section('page-title', 'Reklam Düzenle')
@section('content')
<div class="d-flex align-items-center gap-3 mb-4">
<a href="{{ route('admin.ads.index') }}" class="btn btn-secondary btn-sm">
<i class="bi bi-arrow-left"></i> Reklamlara Dön
</a>
</div>
<div class="row justify-content-center">
<div class="col-xl-6 col-lg-8">
<form method="POST" action="{{ route('admin.ads.update', $ad) }}" enctype="multipart/form-data">
@csrf @method('PUT')
<div class="card">
<div class="card-header">
<i class="bi bi-badge-ad-fill" style="color:#ffd60a"></i>
<h6>{{ $ad->name }}</h6>
</div>
<div class="card-body">
@if($errors->any())
<div class="alert alert-danger py-2" style="font-size:13px">
@foreach($errors->all() as $err)<div>{{ $err }}</div>@endforeach
</div>
@endif
{{-- Önizleme --}}
@if($ad->media_url)
<div class="mb-3 p-3" style="background:var(--bg);border-radius:8px;text-align:center">
@if($ad->type === 'video')
<video src="{{ $ad->media_url }}" controls style="max-width:100%;max-height:220px;border-radius:6px"></video>
@else
<img src="{{ $ad->media_url }}" alt="" style="max-width:100%;max-height:160px;border-radius:6px">
@endif
</div>
@endif
<div class="row g-2 mb-1" style="font-size:13px;color:var(--text2)">
<div class="col-4">Gösterim: <b style="color:var(--text)">{{ number_format($ad->impressions) }}</b></div>
<div class="col-4">Tıklama: <b style="color:var(--text)">{{ number_format($ad->clicks) }}</b></div>
<div class="col-4">CTR: <b style="color:var(--text)">%{{ $ad->ctr }}</b></div>
</div>
<hr style="border-color:var(--border)">
<div class="mb-3">
<label class="form-label">Reklam Adı</label>
<input type="text" name="name" class="form-control" value="{{ old('name', $ad->name) }}" required>
</div>
<div class="row g-2 mb-3">
<div class="col-6">
<label class="form-label">Tür</label>
<select name="type" class="form-select">
<option value="video" {{ $ad->type === 'video' ? 'selected' : '' }}>Video (pre-roll)</option>
<option value="banner" {{ $ad->type === 'banner' ? 'selected' : '' }}>Banner (görsel)</option>
</select>
</div>
<div class="col-6">
<label class="form-label">Konum</label>
<select name="placement" class="form-select">
<option value="preroll" {{ $ad->placement === 'preroll' ? 'selected' : '' }}>Video başı</option>
<option value="home_mid" {{ $ad->placement === 'home_mid' ? 'selected' : '' }}>Ana sayfa orta</option>
<option value="home_bottom" {{ $ad->placement === 'home_bottom' ? 'selected' : '' }}>Ana sayfa alt</option>
</select>
</div>
</div>
<div class="mb-3">
<label class="form-label">Yeni Dosya Yükle <span style="color:var(--text2);font-weight:400">(mevcut dosyanın yerine geçer)</span></label>
<input type="file" name="media_file" class="form-control" accept="{{ $ad->type === 'video' ? 'video/mp4' : 'image/*' }}">
</div>
<div class="mb-3">
<label class="form-label">Dış URL</label>
<input type="url" name="external_url" class="form-control font-monospace" value="{{ old('external_url', $ad->external_url) }}">
</div>
<div class="mb-3">
<label class="form-label">Tıklama URL'si</label>
<input type="url" name="click_url" class="form-control" value="{{ old('click_url', $ad->click_url) }}">
</div>
<div class="row g-2 mb-3">
<div class="col-6">
<label class="form-label">Geçme süresi (sn)</label>
<input type="number" name="skip_after" class="form-control" min="0" max="60" value="{{ old('skip_after', $ad->skip_after) }}">
<div class="form-text">0 = geçilemez</div>
</div>
<div class="col-6">
<label class="form-label">Ağırlık</label>
<input type="number" name="weight" class="form-control" min="1" max="100" value="{{ old('weight', $ad->weight) }}">
</div>
</div>
<div class="row g-2 mb-3">
<div class="col-6">
<label class="form-label">Başlangıç</label>
<input type="datetime-local" name="starts_at" class="form-control"
value="{{ old('starts_at', $ad->starts_at?->format('Y-m-d\TH:i')) }}">
</div>
<div class="col-6">
<label class="form-label">Bitiş</label>
<input type="datetime-local" name="ends_at" class="form-control"
value="{{ old('ends_at', $ad->ends_at?->format('Y-m-d\TH:i')) }}">
</div>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" name="is_active" value="1" id="edit_ad_active" role="switch"
{{ $ad->is_active ? 'checked' : '' }}>
<label class="form-check-label" for="edit_ad_active">Aktif</label>
</div>
<button type="submit" class="btn btn-primary w-100">
<i class="bi bi-floppy"></i> Değişiklikleri Kaydet
</button>
</div>
</div>
</form>
</div>
</div>
@endsection
+291
View File
@@ -0,0 +1,291 @@
@extends('admin.layouts.app')
@section('title', 'Reklamlar')
@section('page-title', 'Reklam Yönetimi')
@section('content')
@if(session('success'))
<div class="alert alert-success py-2 mb-3" style="font-size:14px">
<i class="bi bi-check-circle-fill"></i> {{ session('success') }}
</div>
@endif
@if($errors->any())
<div class="alert alert-danger mb-3" style="font-size:14px">
<div style="font-weight:700;margin-bottom:6px"><i class="bi bi-exclamation-triangle-fill"></i> Reklam eklenemedi:</div>
@foreach($errors->all() as $err)<div> {{ $err }}</div>@endforeach
</div>
@endif
{{-- Özet kartlar --}}
<div class="row g-3 mb-4">
<div class="col-6 col-lg-3">
<div class="card p-3">
<div style="font-size:12px;color:var(--text2)">Toplam Gösterim</div>
<div style="font-size:24px;font-weight:800;color:var(--text)">{{ number_format($stats['total_impressions']) }}</div>
</div>
</div>
<div class="col-6 col-lg-3">
<div class="card p-3">
<div style="font-size:12px;color:var(--text2)">Toplam Tıklama</div>
<div style="font-size:24px;font-weight:800;color:var(--text)">{{ number_format($stats['total_clicks']) }}</div>
</div>
</div>
<div class="col-6 col-lg-3">
<div class="card p-3">
<div style="font-size:12px;color:var(--text2)">Ortalama CTR</div>
<div style="font-size:24px;font-weight:800;color:var(--text)">%{{ $stats['avg_ctr'] }}</div>
</div>
</div>
<div class="col-6 col-lg-3">
<div class="card p-3">
<div style="font-size:12px;color:var(--text2)">Aktif Reklam</div>
<div style="font-size:24px;font-weight:800;color:var(--success)">{{ $stats['active_count'] }}</div>
</div>
</div>
</div>
<div class="row g-4">
{{-- Sol: Ayarlar --}}
<div class="col-lg-4">
<form method="POST" action="{{ route('admin.ads.settings') }}">
@csrf
<div class="card mb-3">
<div class="card-header">
<i class="bi bi-sliders" style="color:var(--accent-lt)"></i>
<h6>Video Reklam Ayarları</h6>
</div>
<div class="card-body">
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" name="vad_enabled" value="1" id="vad_enabled" role="switch"
{{ $settings['vad_enabled'] == '1' ? 'checked' : '' }}>
<label class="form-check-label" for="vad_enabled">Video Reklamları Etkinleştir</label>
</div>
<div class="mb-3">
<label class="form-label">Kaç bölümde bir göster?</label>
<div class="input-group">
<input type="number" name="vad_freq_episodes" class="form-control" min="1" max="50"
value="{{ $settings['vad_freq_episodes'] }}">
<span class="input-group-text">bölüm</span>
</div>
<div class="form-text">2 = her 2 bölümde 1 reklam</div>
</div>
<div class="mb-3">
<label class="form-label">Minimum reklam aralığı</label>
<div class="input-group">
<input type="number" name="vad_freq_minutes" class="form-control" min="1" max="120"
value="{{ $settings['vad_freq_minutes'] }}">
<span class="input-group-text">dakika</span>
</div>
<div class="form-text">5 = 5 dakika içinde en fazla 1 reklam</div>
</div>
<div class="mb-3">
<label class="form-label">Premium teklif oranı</label>
<div class="input-group">
<input type="number" name="vad_upsell_percent" class="form-control" min="0" max="100"
value="{{ $settings['vad_upsell_percent'] }}">
<span class="input-group-text">%</span>
</div>
<div class="form-text">Reklam yerine "Premium'a geç" ekranı gösterme olasılığı. 20 = her 5 reklam slotundan 1'i premium teklifi.</div>
</div>
<hr style="border-color:var(--border)">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="banner_ads_enabled" value="1" id="banner_ads_enabled" role="switch"
{{ $settings['banner_ads_enabled'] == '1' ? 'checked' : '' }}>
<label class="form-check-label" for="banner_ads_enabled">Ana Sayfa Banner Reklamları</label>
</div>
<div class="form-text mb-3">Premium üyeler hiçbir reklamı görmez.</div>
<button type="submit" class="btn btn-primary w-100">
<i class="bi bi-floppy"></i> Ayarları Kaydet
</button>
</div>
</div>
</form>
{{-- Yeni Reklam --}}
<form method="POST" action="{{ route('admin.ads.store') }}" enctype="multipart/form-data">
@csrf
<div class="card">
<div class="card-header">
<i class="bi bi-plus-circle" style="color:var(--success)"></i>
<h6>Yeni Reklam Ekle</h6>
</div>
<div class="card-body">
@if($errors->any())
<div class="alert alert-danger py-2" style="font-size:13px">
@foreach($errors->all() as $err)<div>{{ $err }}</div>@endforeach
</div>
@endif
<div class="mb-3">
<label class="form-label">Reklam Adı</label>
<input type="text" name="name" class="form-control" value="{{ old('name') }}"
placeholder="Örn: Sponsor X — Temmuz kampanya" required>
</div>
<div class="row g-2 mb-3">
<div class="col-6">
<label class="form-label">Tür</label>
<select name="type" class="form-select" id="ad-type-select" onchange="adTypeChanged()">
<option value="video">Video (pre-roll)</option>
<option value="banner">Banner (görsel)</option>
</select>
</div>
<div class="col-6">
<label class="form-label">Konum</label>
<select name="placement" class="form-select" id="ad-placement-select">
<option value="preroll">Video başı</option>
</select>
</div>
</div>
<div class="mb-3">
<label class="form-label">Dosya Yükle <span id="ad-file-hint" style="color:var(--text2);font-weight:400">(MP4, maks 50MB)</span></label>
<input type="file" name="media_file" class="form-control" id="ad-file-input" accept="video/mp4">
</div>
<div class="mb-3">
<label class="form-label">veya Dış URL</label>
<input type="url" name="external_url" class="form-control font-monospace" value="{{ old('external_url') }}"
placeholder="https://cdn.example.com/reklam.mp4">
<div class="form-text">Dosya yüklemek yerine hazır bir URL de verebilirsin.</div>
</div>
<div class="mb-3">
<label class="form-label">Tıklama URL'si</label>
<input type="url" name="click_url" class="form-control" value="{{ old('click_url') }}"
placeholder="https://sponsor-sitesi.com">
<div class="form-text">Reklama tıklanınca açılacak sayfa (boş bırakılabilir).</div>
</div>
<div class="row g-2 mb-3">
<div class="col-6" id="ad-skip-wrap">
<label class="form-label">Geçme süresi (sn)</label>
<input type="number" name="skip_after" class="form-control" min="0" max="60" value="{{ old('skip_after', 5) }}">
<div class="form-text">0 = geçilemez</div>
</div>
<div class="col-6">
<label class="form-label">Ağırlık</label>
<input type="number" name="weight" class="form-control" min="1" max="100" value="{{ old('weight', 10) }}">
<div class="form-text">Yüksek = daha sık</div>
</div>
</div>
<div class="row g-2 mb-3">
<div class="col-6">
<label class="form-label">Başlangıç</label>
<input type="datetime-local" name="starts_at" class="form-control" value="{{ old('starts_at') }}">
</div>
<div class="col-6">
<label class="form-label">Bitiş</label>
<input type="datetime-local" name="ends_at" class="form-control" value="{{ old('ends_at') }}">
</div>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" name="is_active" value="1" id="new_ad_active" role="switch" checked>
<label class="form-check-label" for="new_ad_active">Hemen yayınla</label>
</div>
<button type="submit" class="btn btn-success w-100">
<i class="bi bi-plus-lg"></i> Reklamı Ekle
</button>
</div>
</div>
</form>
</div>
{{-- Sağ: Reklam listesi --}}
<div class="col-lg-8">
<div class="card">
<div class="card-header">
<i class="bi bi-badge-ad-fill" style="color:#ffd60a"></i>
<h6>Reklamlar ({{ $ads->count() }})</h6>
</div>
<div class="card-body p-0">
@if($ads->isEmpty())
<div class="text-center py-5" style="color:var(--text2)">
<i class="bi bi-badge-ad" style="font-size:32px"></i>
<div class="mt-2">Henüz reklam eklenmedi.</div>
</div>
@else
<div class="table-responsive">
<table class="table table-dark-custom mb-0" style="font-size:13px">
<thead>
<tr>
<th>Reklam</th>
<th>Tür / Konum</th>
<th class="text-center">Gösterim</th>
<th class="text-center">Tıklama</th>
<th class="text-center">CTR</th>
<th class="text-center">Durum</th>
<th class="text-end">İşlem</th>
</tr>
</thead>
<tbody>
@foreach($ads as $ad)
<tr>
<td>
<div style="font-weight:600;color:var(--text)">{{ $ad->name }}</div>
<div style="font-size:11px;color:var(--text2)">
Ağırlık: {{ $ad->weight }}
@if($ad->type === 'video') · Geç: {{ $ad->skip_after > 0 ? $ad->skip_after.'sn' : 'kapalı' }} @endif
@if($ad->starts_at || $ad->ends_at)
· 📅 {{ $ad->starts_at?->format('d.m') ?? '∞' }}{{ $ad->ends_at?->format('d.m') ?? '∞' }}
@endif
</div>
</td>
<td>
<span class="badge {{ $ad->type === 'video' ? 'bg-primary' : 'bg-info' }}">{{ $ad->type === 'video' ? 'Video' : 'Banner' }}</span>
<div style="font-size:11px;color:var(--text2);margin-top:2px">
{{ ['preroll' => 'Video başı', 'home_mid' => 'Ana sayfa orta', 'home_bottom' => 'Ana sayfa alt'][$ad->placement] ?? $ad->placement }}
</div>
</td>
<td class="text-center">{{ number_format($ad->impressions) }}</td>
<td class="text-center">{{ number_format($ad->clicks) }}</td>
<td class="text-center">%{{ $ad->ctr }}</td>
<td class="text-center">
<form method="POST" action="{{ route('admin.ads.toggle', $ad) }}" style="display:inline">
@csrf
<button type="submit" class="badge border-0 {{ $ad->is_active ? 'bg-success' : 'bg-secondary' }}" style="cursor:pointer">
{{ $ad->is_active ? 'Aktif' : 'Pasif' }}
</button>
</form>
</td>
<td class="text-end">
<a href="{{ route('admin.ads.edit', $ad) }}" class="btn btn-sm btn-outline-secondary py-0 px-2">
<i class="bi bi-pencil"></i>
</a>
<form method="POST" action="{{ route('admin.ads.destroy', $ad) }}" style="display:inline"
onsubmit="return confirm('Bu reklamı silmek istediğine emin misin?')">
@csrf @method('DELETE')
<button type="submit" class="btn btn-sm btn-outline-danger py-0 px-2">
<i class="bi bi-trash"></i>
</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endif
</div>
</div>
</div>
</div>
@endsection
@push('scripts')
<script>
function adTypeChanged() {
const type = document.getElementById('ad-type-select').value;
const placement = document.getElementById('ad-placement-select');
const fileInput = document.getElementById('ad-file-input');
const fileHint = document.getElementById('ad-file-hint');
const skipWrap = document.getElementById('ad-skip-wrap');
if (type === 'video') {
placement.innerHTML = '<option value="preroll">Video başı</option>';
fileInput.accept = 'video/mp4';
fileHint.textContent = '(MP4, maks 50MB)';
skipWrap.style.display = '';
} else {
placement.innerHTML = '<option value="home_mid">Ana sayfa — orta</option><option value="home_bottom">Ana sayfa — alt</option>';
fileInput.accept = 'image/*';
fileHint.textContent = '(JPG/PNG/WebP, maks 4MB — önerilen 970×120 veya 728×90)';
skipWrap.style.display = 'none';
}
}
</script>
@endpush