Initial commit: Animexe Laravel platform
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user