
========================================
FILE: routes\web.php
========================================
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\AuthController;
use App\Http\Controllers\HomeController;
use App\Http\Controllers\DashboardController;
use App\Http\Controllers\CompetitionController;
use App\Http\Controllers\RegistrationController;
use App\Http\Controllers\ProfileController;
use App\Http\Controllers\NotificationController;
use App\Http\Controllers\OrganizerController;
use App\Http\Controllers\AdminController;
use App\Http\Controllers\ChatController;

Route::get('/', [HomeController::class, 'index'])
    ->name('welcome');

Route::get('/lomba', [CompetitionController::class, 'index'])
    ->name('competitions.index');
Route::get('/lomba/{competition}', [CompetitionController::class, 'show'])
    ->name('competitions.show');

Route::middleware('guest')->group(function () {
    Route::get('/login', [AuthController::class, 'showLogin'])
        ->name('login');
    Route::get('/forgot-password', [AuthController::class, 'showForgotPassword'])
        ->name('password.request');
    Route::post('/login', [AuthController::class, 'login'])
        ->name('login.store');

    Route::get('/register', [AuthController::class, 'showRegister'])    
    ->name('register');
    Route::post('/register', [AuthController::class, 'register'])
        ->name('register.store');
    });

Route::middleware('auth')->group(function () {
    Route::post('/logout', [AuthController::class, 'logout'])
        ->name('logout');
    Route::post('/lomba/{competition}/favorit', [CompetitionController::class, 'toggleFavorite'])
        ->name('competitions.favorite');
    Route::get('/chat', [ChatController::class, 'index'])
        ->name('chat.index');
    Route::post('/chat', [ChatController::class, 'store'])
        ->name('chat.store');

    Route::middleware('role:mahasiswa')->group(function () {
        Route::get('/dashboard', [DashboardController::class, 'index'])
            ->name('dashboard');
        Route::get('/lomba/{competition}/daftar', [RegistrationController::class, 'create'])
            ->name('registrations.create');
        Route::post('/lomba/{competition}/daftar', [RegistrationController::class, 'store'])
            ->name('registrations.store');
        Route::get('/notifikasi', [NotificationController::class, 'index'])
            ->name('notifications.index');
        Route::post('/notifikasi/{notification}/read', [NotificationController::class, 'markRead'])
            ->name('notifications.read');
        Route::get('/profil', [ProfileController::class, 'show'])
            ->name('profile.show');
        Route::get('/profil/data-akun', [ProfileController::class, 'edit'])
            ->name('profile.edit');
        Route::put('/profil/data-akun', [ProfileController::class, 'update'])
            ->name('profile.update');
    });

    Route::middleware('role:penyelenggara')
        ->prefix('penyelenggara')
        ->name('organizer.')
        ->group(function () {

            Route::get('/', [OrganizerController::class, 'index'])
                ->name('dashboard');

            Route::get('/lomba/baru', [OrganizerController::class, 'create'])
                ->name('create');

            Route::post('/lomba', [OrganizerController::class, 'store'])
                ->name('store');

            Route::get('/pengajuan/{order}/edit', [OrganizerController::class, 'edit'])
                ->name('edit');

            Route::put('/pengajuan/{order}', [OrganizerController::class, 'update'])
                ->name('update');

            Route::get('/pembayaran/{order}', [OrganizerController::class, 'payment'])
                ->name('payment');

            Route::post('/pembayaran/{order}', [OrganizerController::class, 'submitPayment'])
                ->name('payment.submit');

            Route::get('/pembayaran/{order}/struk', [OrganizerController::class, 'receipt'])
                ->name('payment.receipt');

            Route::post('/pengajuan/{order}/tutup', [OrganizerController::class, 'closeCompetition'])
                ->name('close');

            // Kelola lomba yang sudah dipublikasikan
            Route::get('/lomba/{order}/kelola', [OrganizerController::class, 'manage'])
                ->name('manage');

            Route::put('/lomba/{order}/kelola', [OrganizerController::class, 'updatePublished'])
                ->name('manage.update');
        });
        
        Route::middleware('role:admin')
        ->prefix('admin')
        ->name('admin.')
        ->group(function () {

        Route::get('/', [AdminController::class, 'index'])
            ->name('dashboard');
        // Pemeriksaan informasi lomba
        Route::post('/pengajuan/{order}/review', [AdminController::class, 'reviewContent'])
            ->name('content.review');
        // Verifikasi pembayaran
        Route::post('/publikasi/{order}/review', [AdminController::class, 'review'])
            ->name('publication.review');
        Route::post('/publikasi/{order}/hapus-poster', [AdminController::class, 'removePoster'])->name('poster.remove');
        });
    });
// AJARA ADMIN COMMAND CENTER - route moderasi
Route::middleware(['auth','role:admin'])->prefix('admin')->name('admin.')->group(function () {
    Route::post('/publikasi/{order}/turunkan', [AdminController::class, 'hidePoster'])->name('poster.hide');
    Route::post('/publikasi/{order}/aktifkan-kembali', [AdminController::class, 'restorePoster'])->name('poster.restore');
    Route::post('/publikasi/{order}/aktifkan-masa-tayang', [AdminController::class, 'activatePromotion'])->name('promotion.activate');
    Route::post('/publikasi/{order}/perpanjang', [AdminController::class, 'extendPromotion'])->name('promotion.extend');
});
Route::middleware('auth')->group(function () {
    Route::get('/notifikasi', [NotificationController::class, 'index'])->name('notifications.index');
    Route::post('/notifikasi/{notification}/read', [NotificationController::class, 'markRead'])->name('notifications.read');
});

========================================
FILE: app\Http\Controllers\AdminController.php
========================================
<?php

namespace App\Http\Controllers;

use App\Models\Competition;
use App\Models\Notification;
use App\Models\PublicationOrder;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;

class AdminController extends Controller
{
    public function index()
    {
        $stats = [
            'users' => User::where('role', 'mahasiswa')->count(),
            'organizers' => User::where('role', 'penyelenggara')->count(),
            'competitions' => Competition::count(),
            'pending_content' => PublicationOrder::where('content_review_status', 'pending')->count(),
            'pending' => PublicationOrder::where('payment_status', 'pending')->count(),
            'published' => Competition::where('status', 'published')->count(),
            'revenue' => (int) PublicationOrder::where('payment_status', 'verified')->sum('amount'),
        ];

        $contentOrders = PublicationOrder::with(['user','competition'])->where('content_review_status','pending')->latest()->get();
        $orders = PublicationOrder::with(['user','competition'])->where('payment_status','pending')->latest()->get();
        $allOrders = PublicationOrder::with(['user','competition'])->latest()->get();
        $organizers = User::where('role','penyelenggara')->withCount('publicationOrders')->with(['publicationOrders.competition'])->orderBy('name')->get();
        $publishedOrders = PublicationOrder::with(['user','competition'])->where('payment_status','verified')->latest()->get();
        $audits = DB::table('publication_audits')->latest()->limit(30)->get();
        $chatUsers = User::where('role','penyelenggara')->orderBy('name')->get();

        return view('admin.dashboard', compact('stats','contentOrders','orders','allOrders','organizers','publishedOrders','audits','chatUsers'));
    }

    public function reviewContent(Request $request, PublicationOrder $order)
    {
        $data = $request->validate([
            'decision' => 'required|in:approve,revision',
            'admin_note' => 'nullable|string|max:2000',
        ]);
        abort_unless($order->content_review_status === 'pending', 422, 'Pengajuan ini sudah diperiksa.');
        $approved = $data['decision'] === 'approve';
        DB::transaction(function () use ($order,$data,$approved) {
            $order->update([
                'content_review_status' => $approved ? 'approved' : 'revision',
                'content_admin_note' => $data['admin_note'] ?? ($approved ? 'Informasi lomba telah disetujui.' : 'Mohon perbaiki informasi lomba.'),
                'content_reviewed_at' => now(),
                'content_reviewed_by' => auth()->id(),
            ]);
            $this->notifyOrganizer($order, $approved ? 'Pengajuan lomba disetujui' : 'Pengajuan lomba perlu direvisi', $approved ? 'Informasi lomba disetujui. Silakan lanjutkan pembayaran publikasi.' : 'Admin meminta revisi: '.($data['admin_note'] ?? '-'), $approved ? 'success' : 'warning');
            $this->audit('content_review', $order, $approved ? 'Pengajuan konten disetujui' : 'Pengajuan konten diminta revisi', $data['admin_note'] ?? null);
        });
        return back()->with('success', $approved ? 'Konten disetujui. Penyelenggara dapat melanjutkan pembayaran.' : 'Permintaan revisi berhasil dikirim.');
    }

    public function review(Request $request, PublicationOrder $order)
    {
        $data = $request->validate(['decision'=>'required|in:approve,reject','admin_note'=>'nullable|string|max:2000']);
        $order->load(['user','competition']);
        abort_unless($order->payment_status === 'pending' && $order->review_status === 'pending', 422, 'Pembayaran ini sudah diproses.');
        abort_unless($order->proof_path && Storage::disk('public')->exists($order->proof_path), 422, 'Bukti transfer belum tersedia.');
        $approved = $data['decision'] === 'approve';
        $days = ['Basic'=>30,'Premium'=>60,'Featured'=>90][$order->package] ?? null;
        abort_if($approved && !$days, 422, 'Paket publikasi tidak valid.');

        DB::transaction(function () use ($order,$data,$approved,$days) {
            $update = [
                'payment_status' => $approved ? 'verified' : 'rejected',
                'review_status' => $approved ? 'approved' : 'rejected',
                'admin_note' => $data['admin_note'] ?? ($approved ? 'Pembayaran diverifikasi Admin AJARA.' : 'Pembayaran ditolak Admin AJARA.'),
            ];
            if ($approved) {
                $start = now();
                $update['promotion_started_at'] = $start;
                $update['promotion_ends_at'] = $start->copy()->addDays($days);
                $order->competition->update(['status'=>'published','admin_hidden_at'=>null,'admin_hidden_by'=>null,'admin_hidden_reason'=>null]);
            } else {
                $order->competition->update(['status'=>'draft']);
            }
            $order->update($update);
            $this->notifyOrganizer($order, $approved ? 'Pembayaran berhasil diverifikasi' : 'Pembayaran ditolak', $approved ? "Pembayaran disetujui. Masa tayang paket {$order->package} aktif selama {$days} hari." : 'Pembayaran belum disetujui: '.($data['admin_note'] ?? '-'), $approved ? 'success' : 'warning');
            $this->audit('payment_review', $order, $approved ? 'Pembayaran diverifikasi' : 'Pembayaran ditolak', $data['admin_note'] ?? null);
        });
        return back()->with('success', $approved ? "Pembayaran diverifikasi dan masa tayang {$days} hari diaktifkan." : 'Pembayaran ditolak.');
    }

    public function hidePoster(Request $request, PublicationOrder $order)
    {
        $data = $request->validate(['reason'=>'required|string|max:2000']);
        $order->load('competition');
        abort_unless($order->competition, 404);
        $order->competition->update(['status'=>'draft','admin_hidden_at'=>now(),'admin_hidden_by'=>auth()->id(),'admin_hidden_reason'=>$data['reason']]);
        $this->notifyOrganizer($order, 'Poster diturunkan oleh Admin AJARA', 'Poster lomba dinonaktifkan oleh Admin. Alasan: '.$data['reason'], 'warning');
        $this->audit('poster_hidden',$order,'Poster diturunkan',$data['reason']);
        return back()->with('success','Poster berhasil diturunkan. Riwayat dan tanggal promosi tetap tersimpan.');
    }

    public function restorePoster(PublicationOrder $order)
    {
        $order->load('competition');
        abort_unless($order->competition && $order->payment_status === 'verified' && $order->promotion_ends_at && now()->lt($order->promotion_ends_at), 422, 'Poster tidak dapat diaktifkan: pembayaran atau masa tayang tidak valid.');
        $order->competition->update(['status'=>'published','admin_hidden_at'=>null,'admin_hidden_by'=>null,'admin_hidden_reason'=>null]);
        $this->notifyOrganizer($order,'Poster diaktifkan kembali','Admin AJARA mengaktifkan kembali poster lomba Anda.','success');
        $this->audit('poster_restored',$order,'Poster diaktifkan kembali',null);
        return back()->with('success','Poster berhasil ditayangkan kembali.');
    }

    public function activatePromotion(PublicationOrder $order)
    {
        abort_unless($order->payment_status === 'verified' && $order->review_status === 'approved', 422, 'Pembayaran belum disetujui.');
        abort_unless(!$order->promotion_started_at || !$order->promotion_ends_at, 422, 'Masa tayang sudah pernah diaktifkan. Gunakan fitur perpanjang.');
        $days = ['Basic'=>30,'Premium'=>60,'Featured'=>90][$order->package] ?? null;
        abort_unless($days, 422, 'Paket publikasi tidak valid.');
        $start = now();
        $order->update(['promotion_started_at'=>$start,'promotion_ends_at'=>$start->copy()->addDays($days)]);
        $this->notifyOrganizer($order, 'Masa tayang diaktifkan Admin', "Admin mengaktifkan masa tayang {$order->package} selama {$days} hari.", 'success');
        $this->audit('promotion_activated',$order,'Masa tayang diaktifkan manual',"{$days} hari");
        return back()->with('success', "Masa tayang {$days} hari berhasil diaktifkan.");
    }

    public function extendPromotion(Request $request, PublicationOrder $order)
    {
        $data = $request->validate(['days'=>'required|integer|min:1|max:365']);
        abort_unless($order->payment_status === 'verified' && $order->promotion_started_at, 422, 'Masa tayang belum pernah diaktifkan.');
        $base = $order->promotion_ends_at && $order->promotion_ends_at->isFuture() ? $order->promotion_ends_at->copy() : now();
        $order->update(['promotion_ends_at'=>$base->addDays((int)$data['days'])]);
        $this->notifyOrganizer($order,'Masa tayang diperpanjang',"Admin memperpanjang masa tayang poster selama {$data['days']} hari.",'success');
        $this->audit('promotion_extended',$order,'Masa tayang diperpanjang',$data['days'].' hari');
        return back()->with('success','Masa tayang berhasil diperpanjang.');
    }

    public function removePoster(Request $request, PublicationOrder $order)
    {
        $data = $request->validate(['reason'=>'required|string|max:2000']);
        $order->load('competition');
        abort_unless($order->competition,404);
        $competition = $order->competition;
        if ($competition->banner) Storage::disk('public')->delete($competition->banner);
        $competition->update(['banner'=>null,'status'=>'draft','admin_hidden_at'=>now(),'admin_hidden_by'=>auth()->id(),'admin_hidden_reason'=>$data['reason']]);
        $this->notifyOrganizer($order,'Poster dihapus oleh Admin AJARA','File poster dihapus. Alasan: '.$data['reason'],'danger');
        $this->audit('poster_deleted',$order,'File poster dihapus',$data['reason']);
        return back()->with('success','File poster dihapus. Data lomba dan riwayat transaksi tetap dipertahankan.');
    }

    private function notifyOrganizer(PublicationOrder $order, string $title, string $message, string $type='info'): void
    {
        Notification::create(['user_id'=>$order->user_id,'title'=>$title,'message'=>$message,'type'=>$type]);
    }

    private function audit(string $action, PublicationOrder $order, string $description, ?string $detail): void
    {
        DB::table('publication_audits')->insert([
            'admin_id'=>auth()->id(),'user_id'=>$order->user_id,'publication_order_id'=>$order->id,
            'competition_id'=>$order->competition_id,'action'=>$action,'description'=>$description,
            'detail'=>$detail,'created_at'=>now(),'updated_at'=>now(),
        ]);
    }
}

========================================
FILE: app\Http\Controllers\OrganizerController.php
========================================
<?php

namespace App\Http\Controllers;

use App\Models\Competition;
use App\Models\PublicationOrder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class OrganizerController extends Controller
{
    private const PACKAGES = [
        'Basic' => 49000,
        'Premium' => 99000,
        'Featured' => 199000,
    ];
    public function index()
    {
        $orders = auth()->user()
            ->publicationOrders()
            ->with('competition')
            ->latest()
            ->get();

        return view('organizer.dashboard', compact('orders'));
    }

    public function create()
    {
        return view('organizer.create', [
            'packages' => self::PACKAGES
        ]);
    }

    public function store(Request $r)
    {
        $d = $r->validate([
            'title' => 'required|string|max:180',
            'organizer' => 'required|string|max:180',
            'competition_category' => 'required|string|max:100',
            'competition_level' => 'required|string|max:50',
            'delivery_mode' => 'required|in:Online,Offline,Hybrid',
            'location' => 'nullable|string|max:180',
            'description' => 'required|string|max:10000',
            'requirements' => 'required|string|max:10000',
            'benefits' => 'nullable|string|max:5000',
            'registration_start' => 'required|date',
            'registration_end' => 'required|date|after_or_equal:registration_start',
            'event_start' => 'nullable|date',
            'event_end' => 'nullable|date|after_or_equal:event_start',
            'contact' => 'required|string|max:180',
            'banner' => 'required|image|mimes:jpg,jpeg,png,webp|max:5120',
            'package' => 'required|in:Basic,Premium,Featured',
        ]);

        $mode = $d['delivery_mode'];

        $banner = $r->file('banner')
            ->store('competition-posters', 'public');

        $competition = Competition::create([
            'title' => $d['title'],
            'organizer' => $d['organizer'],
            'category' => $d['competition_level'] === 'Internasional'
                ? 'Internasional'
                : ($d['competition_level'] === 'Nasional'
                    ? 'Nasional' : 'Kampus'),
            'competition_category' => $d['competition_category'],
            'competition_level' => $d['competition_level'],
            'mode' => $mode === 'Offline' ? 'Offline' : 'Online',
            'delivery_mode' => $mode,
            'location' => $d['location'] ?? ($mode === 'Online' ? 'Online' : null),
            'description' => $d['description'],
            'requirements' => $d['requirements'],
            'benefits' => $d['benefits'] ?? null,
            'registration_start' => $d['registration_start'],
            'registration_end' => $d['registration_end'],
            'event_start' => $d['event_start'] ?? null,
            'event_end' => $d['event_end'] ?? null,
            'contact' => $d['contact'],
            'banner' => $banner,
            'status' => 'draft',
        ]);

        PublicationOrder::create([
            'user_id' => auth()->id(),
            'competition_id' => $competition->id,
            'package' => $d['package'],
            'amount' => self::PACKAGES[$d['package']],

            // Pemeriksaan informasi lomba
            'content_review_status' => 'pending',
            'content_admin_note' => null,
            'content_reviewed_at' => null,
            'content_reviewed_by' => null,

            // Pembayaran
            'payment_status' => 'unpaid',
            'review_status' => 'pending',
        ]);
        return redirect()
            ->route('organizer.dashboard')
            ->with(
                'success', 
                'Pengajuan berhasil dikirim. Silakan tunggu pemeriksaan Admin AJARA sebelum melakukan pembayaran.');
    }

    public function edit(PublicationOrder $order)
{
    abort_unless($order->user_id === auth()->id(), 403);

    abort_unless(
        $order->content_review_status === 'revision',
        403,
        'Pengajuan ini tidak sedang menunggu revisi.'
    );

    $order->load('competition');
    $competition = $order->competition;

    return view('organizer.edit', compact('order', 'competition'));
}

public function update(Request $r, PublicationOrder $order)
{
    abort_unless($order->user_id === auth()->id(), 403);

    abort_unless(
        $order->content_review_status === 'revision',
        403,
        'Pengajuan ini tidak sedang menunggu revisi.'
    );

    $d = $r->validate([
        'title' => 'required|string|max:180',
        'organizer' => 'required|string|max:180',
        'competition_category' => 'required|string|max:100',
        'competition_level' => 'required|string|max:50',
        'delivery_mode' => 'required|in:Online,Offline,Hybrid',
        'location' => 'nullable|string|max:180',
        'description' => 'required|string|max:10000',
        'requirements' => 'required|string|max:10000',
        'benefits' => 'nullable|string|max:5000',
        'registration_start' => 'required|date',
        'registration_end' => 'required|date|after_or_equal:registration_start',
        'event_start' => 'nullable|date',
        'event_end' => 'nullable|date|after_or_equal:event_start',
        'contact' => 'required|string|max:180',
        'banner' => 'nullable|image|mimes:jpg,jpeg,png,webp|max:5120',
    ]);

    $competition = $order->competition;
    $oldBanner = $competition->banner;

    // Jika poster baru diunggah, simpan poster baru.
    // Jika tidak, gunakan poster lama.
    $banner = $oldBanner;

    if ($r->hasFile('banner')) {
        $banner = $r->file('banner')
            ->store('competition-posters', 'public');
    }

    $mode = $d['delivery_mode'];

    $competition->update([
        'title' => $d['title'],
        'organizer' => $d['organizer'],
        'category' => $d['competition_level'] === 'Internasional'
            ? 'Internasional'
            : ($d['competition_level'] === 'Nasional'
                ? 'Nasional' : 'Kampus'),
        'competition_category' => $d['competition_category'],
        'competition_level' => $d['competition_level'],
        'mode' => $mode === 'Offline' ? 'Offline' : 'Online',
        'delivery_mode' => $mode,
        'location' => $d['location'] ?? ($mode === 'Online' ? 'Online' : null),
        'description' => $d['description'],
        'requirements' => $d['requirements'],
        'benefits' => $d['benefits'] ?? null,
        'registration_start' => $d['registration_start'],
        'registration_end' => $d['registration_end'],
        'event_start' => $d['event_start'] ?? null,
        'event_end' => $d['event_end'] ?? null,
        'contact' => $d['contact'],
        'banner' => $banner,
        'status' => 'draft',
    ]);

    // Kirim kembali ke antrean pemeriksaan Admin.
    $order->update([
        'content_review_status' => 'pending',
        'content_admin_note' => null,
        'content_reviewed_at' => null,
        'content_reviewed_by' => null,
    ]);

    // Hapus poster lama hanya jika poster baru berhasil diunggah.
    if ($r->hasFile('banner') && $oldBanner) {
        Storage::disk('public')->delete($oldBanner);
    }

    return redirect()
        ->route('organizer.dashboard')
        ->with('success', 'Perbaikan berhasil dikirim. Pengajuan menunggu pemeriksaan ulang Admin AJARA.');
}

public function payment(PublicationOrder $order)
{
    abort_unless($order->user_id === auth()->id(), 403);

    abort_unless(
        $order->content_review_status === 'approved',
        403,
        'Pengajuan lomba belum disetujui Admin AJARA.'
    );

    abort_if(
        $order->payment_status === 'verified',
        403,
        'Pembayaran sudah diverifikasi.'
    );

    return view('organizer.payment', compact('order'));
}
    public function receipt(PublicationOrder $order)
    {
        abort_unless($order->user_id === auth()->id(), 403);

        $order->load(['user', 'competition']);

        return view('organizer.receipt', compact('order'));
    }

public function submitPayment(Request $r, PublicationOrder $order)
{
    abort_unless($order->user_id === auth()->id(), 403);

    abort_unless(
        $order->content_review_status === 'approved',
        403,
        'Pengajuan lomba belum disetujui Admin AJARA.'
    );

    abort_if(
        $order->payment_status === 'verified',
        403,
        'Pembayaran sudah diverifikasi dan tidak dapat diubah.'
    );

    $d = $r->validate([
        'proof' => 'required|image|mimes:jpg,jpeg,png,webp|max:5120',
    ]);

    $oldPath = $order->proof_path;

    $path = $r->file('proof')
        ->store('payment-proofs', 'public');

    $order->update([
        'proof_path' => $path,
        'payment_status' => 'pending',
        'review_status' => 'pending',
        'paid_at' => now(),
        'admin_note' => null,
    ]);

    if ($oldPath && $oldPath !== $path) {
        Storage::disk('public')->delete($oldPath);
    }

    return redirect()
        ->route('organizer.dashboard')
        ->with(
            'success',
            'Bukti pembayaran berhasil dikirim. Tunggu verifikasi Admin AJARA.'
        );
}

public function closeCompetition(PublicationOrder $order)
{
    abort_unless($order->user_id === auth()->id(), 403);

    $order->load('competition');
    $competition = $order->competition;

    abort_unless(
        $order->content_review_status === 'approved'
        && $order->payment_status === 'verified'
        && $order->review_status === 'approved'
        && $competition
        && $competition->status === 'published',
        403,
        'Lomba hanya dapat ditutup setelah publikasi aktif dan pembayaran terverifikasi.'
    );

    $competition->update([
        'status' => 'closed',
        'closure_type' => 'manual',
        'closed_at' => now(),
        'closed_by' => auth()->id(),
    ]);

    return redirect()->route('organizer.dashboard')
        ->with('success', 'Lomba berhasil ditutup. Lomba tetap dapat dilihat mahasiswa, tetapi pendaftaran tidak tersedia.');
}

public function manage(PublicationOrder $order)
{
    abort_unless($order->user_id === auth()->id(), 403);

    $order->load('competition');
    $competition = $order->competition;
    abort_unless(
        $order->promotion_started_at
        && $order->promotion_ends_at
        && now()->lt($order->promotion_ends_at),
        403,
        'Masa promosi lomba telah berakhir atau belum aktif.'
    );

    abort_unless(
        $order->content_review_status === 'approved'
        && $order->payment_status === 'verified'
        && $order->review_status === 'approved'
        && $competition
        && $competition->status === 'published',
        403,
        'Lomba ini belum dapat dikelola.'
    );

    return view('organizer.manage', compact('order', 'competition'));
}

public function updatePublished(Request $r, PublicationOrder $order)
{
    abort_unless($order->user_id === auth()->id(), 403);

    $order->load('competition');
    $competition = $order->competition;
    // Pastikan masa promosi masih aktif.
    abort_unless(
        $order->promotion_started_at
        && $order->promotion_ends_at
        && now()->lt($order->promotion_ends_at),
        403,
        'Masa promosi lomba telah berakhir atau belum aktif.'
    );

    abort_unless(
        $order->content_review_status === 'approved'
        && $order->payment_status === 'verified'
        && $order->review_status === 'approved'
        && $competition
        && $competition->status === 'published',
        403,
        'Lomba ini tidak dapat diperbarui.'
    );

    $d = $r->validate([
        'title' => 'required|string|max:180',
        'organizer' => 'required|string|max:180',
        'competition_category' => 'required|string|max:100',
        'competition_level' => 'required|string|max:50',
        'delivery_mode' => 'required|in:Online,Offline,Hybrid',
        'location' => 'nullable|string|max:180',
        'description' => 'required|string|max:10000',
        'requirements' => 'required|string|max:10000',
        'benefits' => 'nullable|string|max:5000',
        'registration_start' => 'required|date',
        'registration_end' => 'required|date|after_or_equal:registration_start',
        'event_start' => 'nullable|date',
        'event_end' => 'nullable|date|after_or_equal:event_start',
        'contact' => 'required|string|max:180',
        'banner' => 'nullable|image|mimes:jpg,jpeg,png,webp|max:5120',
    ]);

    $oldBanner = $competition->banner;
    $banner = $oldBanner;

    if ($r->hasFile('banner')) {
        $banner = $r->file('banner')->store('competition-posters', 'public');
    }

    $mode = $d['delivery_mode'];

    $competition->update([
        'title' => $d['title'],
        'organizer' => $d['organizer'],
        'category' => $d['competition_level'] === 'Internasional'
            ? 'Internasional'
            : ($d['competition_level'] === 'Nasional' ? 'Nasional' : 'Kampus'),
        'competition_category' => $d['competition_category'],
        'competition_level' => $d['competition_level'],
        'mode' => $mode === 'Offline' ? 'Offline' : 'Online',
        'delivery_mode' => $mode,
        'location' => $d['location'] ?? ($mode === 'Online' ? 'Online' : null),
        'description' => $d['description'],
        'requirements' => $d['requirements'],
        'benefits' => $d['benefits'] ?? null,
        'registration_start' => $d['registration_start'],
        'registration_end' => $d['registration_end'],
        'event_start' => $d['event_start'] ?? null,
        'event_end' => $d['event_end'] ?? null,
        'contact' => $d['contact'],
        'banner' => $banner,
    ]);

    if ($r->hasFile('banner') && $oldBanner) {
        Storage::disk('public')->delete($oldBanner);
    }

    return redirect()
        ->route('organizer.dashboard')
        ->with('success', 'Informasi lomba berhasil diperbarui.');
}

}

========================================
FILE: app\Http\Controllers\ChatController.php
========================================
<?php

namespace App\Http\Controllers;

use App\Models\ChatMessage;
use App\Models\Notification;
use App\Models\User;
use Illuminate\Http\Request;

class ChatController extends Controller
{
    public function index(Request $request)
    {
        $isAdmin = $request->user()->role === 'admin';
        abort_unless($isAdmin || $request->user()->role === 'penyelenggara', 403, 'Chat hanya tersedia untuk Admin dan penyelenggara.');

        if ($isAdmin) {
            $users = User::where('role', 'penyelenggara')->withCount('chatMessages')->orderBy('name')->get();
            $target = $request->filled('user')
                ? User::where('role', 'penyelenggara')->findOrFail($request->integer('user'))
                : $users->first();
        } else {
            $users = collect();
            $target = $request->user();
        }

        $messages = $target
            ? $target->chatMessages()->oldest()->take(200)->get()
            : collect();

        if ($isAdmin && $target) {
            $target->chatMessages()->where('sender_role', 'user')->whereNull('read_at')->update(['read_at' => now()]);
        } elseif (!$isAdmin) {
            $target->chatMessages()->where('sender_role', 'admin')->whereNull('read_at')->update(['read_at' => now()]);
        }

        return view('chat.index', [
            'messages' => $messages,
            'users' => $users,
            'selectedUser' => $target,
            'isAdmin' => $isAdmin,
        ]);
    }

    public function store(Request $request)
    {
        $data = $request->validate([
            'message' => 'required|string|max:3000',
            'user_id' => 'nullable|integer|exists:users,id',
        ]);

        $isAdmin = $request->user()->role === 'admin';
        abort_unless($isAdmin || $request->user()->role === 'penyelenggara', 403);

        $targetId = $isAdmin ? (int) ($data['user_id'] ?? 0) : $request->user()->id;
        abort_unless($targetId && User::whereKey($targetId)->where('role', 'penyelenggara')->exists(), 422, 'Pilih penyelenggara yang valid.');

        ChatMessage::create([
            'user_id' => $targetId,
            'sender_role' => $isAdmin ? 'admin' : 'user',
            'message' => $data['message'],
        ]);

        if ($isAdmin) {
            Notification::create([
                'user_id' => $targetId,
                'title' => 'Pesan baru dari Admin AJARA',
                'message' => 'Admin mengirim pesan. Buka menu Chat AJARA untuk membalas.',
                'type' => 'info',
            ]);
        } else {
            User::where('role', 'admin')->pluck('id')->each(function ($adminId) {
                Notification::create([
                    'user_id' => $adminId,
                    'title' => 'Pesan baru dari penyelenggara',
                    'message' => 'Ada pesan baru di Chat AJARA.',
                    'type' => 'info',
                ]);
            });
        }

        return redirect()->route('chat.index', $isAdmin ? ['user' => $targetId] : [])->with('success', 'Pesan berhasil dikirim.');
    }
}

========================================
FILE: app\Http\Controllers\NotificationController.php
========================================
<?php

namespace App\Http\Controllers;

use App\Models\Notification;

class NotificationController extends Controller
{
    public function index()
    {
        $notifications = Notification::where('user_id', auth()->id())->latest()->get();
        return view('notifications.index', compact('notifications'));
    }

    public function markRead(Notification $notification)
    {
        abort_unless($notification->user_id === auth()->id(), 403);
        $notification->update(['read_at' => now()]);
        return back();
    }
}


========================================
FILE: app\Models\Competition.php
========================================
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Competition extends Model
{
    protected $fillable = [
        'title', 'organizer', 'category', 'competition_category',
        'competition_level', 'banner', 'description', 'requirements',
        'registration_start', 'registration_end', 'event_start',
        'event_end', 'registration_url', 'location', 'contact',
        'benefits', 'mode', 'delivery_mode', 'fee_amount',
        'rating', 'review_count', 'views', 'is_recommended',
        'status', 'closure_type', 'closed_at', 'closed_by', 'admin_hidden_at', 'admin_hidden_by', 'admin_hidden_reason',
        'banner_removed_at', 'banner_removed_by',
        'banner_removal_reason',
    ];

    protected $casts = [
        'registration_start' => 'date',
        'registration_end' => 'date',
        'event_start' => 'date',
        'event_end' => 'date',
        'is_recommended' => 'boolean',
        'closed_at' => 'datetime',
        'admin_hidden_at' => 'datetime',
        'banner_removed_at' => 'datetime',
    ];

    public function registrations(): HasMany
    {
        return $this->hasMany(Registration::class);
    }

    public function publicationOrders(): HasMany
    {
        return $this->hasMany(PublicationOrder::class);
    }
}

========================================
FILE: app\Models\PublicationOrder.php
========================================
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class PublicationOrder extends Model
{
    protected $fillable = [
        'user_id',
        'competition_id',
        'package',
        'amount',

        // Pemeriksaan informasi lomba
        'content_review_status',
        'content_admin_note',
        'content_reviewed_at',
        'content_reviewed_by',

        // Pembayaran publikasi
        'proof_path',
        'payment_status',
        'review_status',
        'admin_note',
        'paid_at',

        'promotion_started_at',
        'promotion_ends_at',
    ];

    protected $casts = [
        'paid_at' => 'datetime',
        'content_reviewed_at' => 'datetime',
        'promotion_started_at' => 'datetime',
        'promotion_ends_at' => 'datetime',
    ];

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    public function competition(): BelongsTo
    {
        return $this->belongsTo(Competition::class);
    }

    public function contentReviewer(): BelongsTo
    {
        return $this->belongsTo(User::class, 'content_reviewed_by');
    }
}


========================================
FILE: app\Models\ChatMessage.php
========================================
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo;
class ChatMessage extends Model {protected $fillable=['user_id','sender_role','message','read_at'];protected $casts=['read_at'=>'datetime'];public function user():BelongsTo{return $this->belongsTo(User::class);}}


========================================
FILE: app\Models\Notification.php
========================================
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Notification extends Model
{
    protected $fillable = ['user_id', 'title', 'message', 'type', 'read_at'];
    protected $casts = ['read_at' => 'datetime'];
    public function user(): BelongsTo { return $this->belongsTo(User::class); }
}


========================================
FILE: resources\views\admin\dashboard.blade.php
========================================
@extends('layouts.app')
@section('title','AJARA Ã‚Â· Admin Command Center')
@section('content')
<main class="min-h-screen bg-[#f4f7fb] py-8">
<div class="mx-auto max-w-[1500px] px-4 sm:px-6 lg:px-8">
    @if(session('success'))<div class="mb-5 rounded-2xl border border-emerald-200 bg-emerald-50 px-5 py-4 font-semibold text-emerald-800">{{ session('success') }}</div>@endif
    @if($errors->any())<div class="mb-5 rounded-2xl border border-rose-200 bg-rose-50 px-5 py-4 text-rose-800">@foreach($errors->all() as $error)<p>{{ $error }}</p>@endforeach</div>@endif
    <section class="relative overflow-hidden rounded-[2rem] bg-gradient-to-br from-[#063b45] via-[#075b62] to-[#102c55] p-7 text-white shadow-xl sm:p-10">
        <div class="pointer-events-none absolute -right-20 -top-24 h-80 w-80 rounded-full bg-cyan-300/20 blur-3xl"></div><div class="pointer-events-none absolute bottom-0 right-1/3 h-48 w-48 rounded-full bg-amber-300/10 blur-3xl"></div>
        <div class="relative flex flex-wrap items-end justify-between gap-5"><div><p class="text-xs font-black tracking-[.28em] text-amber-200">AJARA / ADMINISTRATOR</p><h1 class="mt-3 text-3xl font-black tracking-tight sm:text-4xl">Command Center</h1><p class="mt-2 max-w-2xl text-sm text-cyan-50/80">Pusat kendali penyelenggara, publikasi, pembayaran, moderasi poster, dan komunikasi.</p></div><a href="{{ route('chat.index') }}" class="rounded-xl border border-white/25 bg-white/10 px-5 py-3 font-bold backdrop-blur hover:bg-white/20">Ã¢Å“â€° Pusat pesan</a></div>
        <div class="relative mt-8 grid gap-3 sm:grid-cols-2 xl:grid-cols-4">
            @foreach([['Mahasiswa',$stats['users']],['Penyelenggara',$stats['organizers']],['Lomba tayang',$stats['published']],['Perlu tindakan',$stats['pending_content']+$stats['pending']]] as $s)
            <div class="rounded-2xl border border-white/15 bg-white/10 p-4 backdrop-blur"><p class="text-sm text-cyan-50/75">{{ $s[0] }}</p><p class="mt-2 text-3xl font-black">{{ number_format($s[1]) }}</p></div>
            @endforeach
        </div>
    </section>

    <div class="mt-5 grid gap-4 md:grid-cols-3"><div class="rounded-2xl bg-white p-5 shadow-sm"><p class="text-sm text-slate-500">Total lomba terdaftar</p><p class="mt-1 text-2xl font-extrabold text-slate-900">{{ number_format($stats['competitions']) }}</p></div><div class="rounded-2xl bg-white p-5 shadow-sm"><p class="text-sm text-slate-500">Menunggu verifikasi pembayaran</p><p class="mt-1 text-2xl font-extrabold text-amber-600">{{ number_format($stats['pending']) }}</p></div><div class="rounded-2xl bg-white p-5 shadow-sm"><p class="text-sm text-slate-500">Pembayaran terverifikasi</p><p class="mt-1 text-2xl font-extrabold text-emerald-700">Rp{{ number_format($stats['revenue'],0,',','.') }}</p></div></div>

    <nav class="sticky top-2 z-20 mt-7 flex flex-wrap gap-2 rounded-2xl border border-slate-200 bg-white/90 p-3 shadow-sm backdrop-blur"><a class="rounded-xl bg-slate-100 px-4 py-2 text-sm font-bold text-slate-700" href="#review">Review</a><a class="rounded-xl bg-slate-100 px-4 py-2 text-sm font-bold text-slate-700" href="#organizers">Penyelenggara</a><a class="rounded-xl bg-slate-100 px-4 py-2 text-sm font-bold text-slate-700" href="#posters">Kontrol poster</a><a class="rounded-xl bg-slate-100 px-4 py-2 text-sm font-bold text-slate-700" href="#transactions">Transaksi</a><a class="rounded-xl bg-slate-100 px-4 py-2 text-sm font-bold text-slate-700" href="#audit">Audit</a></nav>

    <section id="review" class="mt-7 grid gap-5 xl:grid-cols-2">
      <div class="overflow-hidden rounded-3xl bg-white shadow-sm"><div class="border-b p-5"><h2 class="text-xl font-extrabold text-slate-900">Pemeriksaan pengajuan</h2><p class="mt-1 text-sm text-slate-500">Setujui atau minta revisi informasi lomba.</p></div><div class="divide-y">@forelse($contentOrders as $o)<article class="p-5"><div class="flex flex-wrap justify-between gap-2"><div><h3 class="font-bold text-slate-900">{{ $o->competition->title ?? 'Lomba dihapus' }}</h3><p class="text-sm text-slate-500">{{ $o->user->name ?? '-' }} Ã‚Â· {{ $o->user->email ?? '-' }}</p></div><span class="h-fit rounded-full bg-amber-100 px-3 py-1 text-xs font-bold text-amber-800">Menunggu review</span></div><div class="mt-3 flex flex-wrap gap-3 text-sm text-slate-600"><span>{{ $o->package }}</span><span>Rp{{ number_format($o->amount,0,',','.') }}</span></div>@if($o->competition?->banner)<a target="_blank" href="{{ asset('storage/'.$o->competition->banner) }}" class="mt-3 inline-block"><img class="h-36 max-w-full rounded-xl border object-contain" src="{{ asset('storage/'.$o->competition->banner) }}" alt="Poster"></a>@endif<form method="POST" action="{{ route('admin.content.review',$o) }}" class="mt-4 grid gap-2">@csrf<textarea name="admin_note" rows="2" placeholder="Catatan untuk penyelenggara" class="w-full rounded-xl border border-slate-200 p-3 text-sm"></textarea><div class="flex flex-wrap gap-2"><button name="decision" value="approve" class="rounded-xl bg-emerald-700 px-4 py-2 text-sm font-bold text-white">Setujui</button><button name="decision" value="revision" class="rounded-xl bg-amber-500 px-4 py-2 text-sm font-bold text-white">Minta revisi</button></div></form></article>@empty<div class="p-8 text-center text-sm text-slate-500">Tidak ada pengajuan menunggu.</div>@endforelse</div></div>
      <div class="overflow-hidden rounded-3xl bg-white shadow-sm"><div class="border-b p-5"><h2 class="text-xl font-extrabold text-slate-900">Verifikasi pembayaran</h2><p class="mt-1 text-sm text-slate-500">Bukti transfer, nominal, dan aktivasi masa tayang.</p></div><div class="divide-y">@forelse($orders as $o)<article class="p-5"><h3 class="font-bold text-slate-900">{{ $o->competition->title ?? '-' }}</h3><p class="text-sm text-slate-500">{{ $o->user->name ?? '-' }} Ã‚Â· {{ $o->package }} Ã‚Â· Rp{{ number_format($o->amount,0,',','.') }}</p>@if($o->proof_path)<a target="_blank" href="{{ asset('storage/'.$o->proof_path) }}" class="mt-2 inline-block font-bold text-teal-700 underline">Buka bukti transfer Ã¢â€ â€”</a>@endif<form method="POST" action="{{ route('admin.publication.review',$o) }}" class="mt-3 grid gap-2">@csrf<textarea name="admin_note" rows="2" placeholder="Catatan verifikasi" class="w-full rounded-xl border border-slate-200 p-3 text-sm"></textarea><div class="flex gap-2"><button name="decision" value="approve" class="rounded-xl bg-emerald-700 px-4 py-2 text-sm font-bold text-white">Verifikasi & aktifkan tayang</button><button name="decision" value="reject" class="rounded-xl bg-rose-600 px-4 py-2 text-sm font-bold text-white">Tolak</button></div></form></article>@empty<div class="p-8 text-center text-sm text-slate-500">Tidak ada pembayaran menunggu.</div>@endforelse</div></div>
    </section>

    <section id="organizers" class="mt-7 overflow-hidden rounded-3xl bg-white shadow-sm"><div class="flex flex-wrap items-center justify-between gap-3 border-b p-5"><div><h2 class="text-xl font-extrabold text-slate-900">Direktori penyelenggara</h2><p class="text-sm text-slate-500">Seluruh akun penyelenggara dan jumlah pengajuannya.</p></div><span class="rounded-full bg-teal-50 px-3 py-1 text-sm font-bold text-teal-800">{{ $organizers->count() }} akun</span></div><div class="overflow-x-auto"><table class="w-full min-w-[700px] text-left text-sm"><thead class="bg-slate-50 text-xs uppercase tracking-wide text-slate-500"><tr><th class="p-4">Penyelenggara</th><th class="p-4">Email</th><th class="p-4">Total pengajuan</th><th class="p-4">Aksi</th></tr></thead><tbody class="divide-y">@forelse($organizers as $u)<tr><td class="p-4 font-bold text-slate-900">{{ $u->name }}</td><td class="p-4 text-slate-600">{{ $u->email }}</td><td class="p-4">{{ $u->publication_orders_count }}</td><td class="p-4"><a href="{{ route('chat.index',['user'=>$u->id]) }}" class="rounded-lg bg-teal-700 px-3 py-2 font-bold text-white">Chat</a></td></tr>@empty<tr><td colspan="4" class="p-8 text-center text-slate-500">Belum ada akun penyelenggara.</td></tr>@endforelse</tbody></table></div></section>

    <section id="posters" class="mt-7 overflow-hidden rounded-3xl bg-white shadow-sm"><div class="border-b p-5"><h2 class="text-xl font-extrabold text-slate-900">Monitoring & moderasi poster</h2><p class="text-sm text-slate-500">Admin dapat menurunkan, mengaktifkan kembali, menghapus file, dan memperpanjang masa tayang.</p></div><div class="divide-y">@forelse($publishedOrders as $o)@php($c=$o->competition)<article class="grid gap-4 p-5 lg:grid-cols-[150px_1fr_330px]">@if($c?->banner)<a href="{{ asset('storage/'.$c->banner) }}" target="_blank"><img src="{{ asset('storage/'.$c->banner) }}" class="h-40 w-full rounded-xl bg-slate-100 object-contain" alt="Poster"></a>@else<div class="grid h-40 place-items-center rounded-xl bg-slate-100 text-xs text-slate-500">Poster tidak tersedia</div>@endif<div><h3 class="font-extrabold text-slate-900">{{ $c->title ?? 'Lomba dihapus' }}</h3><p class="text-sm text-slate-500">{{ $o->user->name ?? '-' }} Ã‚Â· {{ $o->package }}</p><p class="mt-2 text-sm">Status: <b>{{ $c->status ?? '-' }}</b></p><p class="text-sm">Mulai: {{ $o->promotion_started_at?->format('d M Y') ?? '-' }} Ã‚Â· Berakhir: {{ $o->promotion_ends_at?->format('d M Y') ?? '-' }}</p>@if($c?->admin_hidden_at)<p class="mt-2 rounded-lg bg-rose-50 p-2 text-sm text-rose-700">Diturunkan: {{ $c->admin_hidden_reason }}</p>@endif</div><div class="flex flex-col gap-2">@if($c?->status === 'published')<form method="POST" action="{{ route('admin.poster.hide',$o) }}">@csrf<input name="reason" required placeholder="Alasan menurunkan poster" class="mb-2 w-full rounded-lg border p-2 text-sm"><button class="w-full rounded-lg bg-amber-500 px-3 py-2 text-sm font-bold text-white">Turunkan poster</button></form>@else<form method="POST" action="{{ route('admin.poster.restore',$o) }}">@csrf<button class="w-full rounded-lg bg-emerald-700 px-3 py-2 text-sm font-bold text-white">Aktifkan kembali</button></form>@endif @if(!$o->promotion_started_at || !$o->promotion_ends_at)<form method="POST" action="{{ route('admin.promotion.activate',$o) }}">@csrf<button class="w-full rounded-lg bg-teal-700 px-3 py-2 text-sm font-bold text-white">Aktifkan masa tayang paket</button></form>@endif<form method="POST" action="{{ route('admin.promotion.extend',$o) }}" class="flex gap-2">@csrf<input type="number" name="days" min="1" max="365" required placeholder="Hari" class="w-24 rounded-lg border p-2 text-sm"><button class="flex-1 rounded-lg bg-slate-800 px-3 py-2 text-sm font-bold text-white">Tambah hari</button></form><form method="POST" action="{{ route('admin.poster.remove',$o) }}" onsubmit="return confirm('Hapus file poster secara permanen? Riwayat transaksi tetap disimpan.');">@csrf<input name="reason" required placeholder="Alasan hapus file" class="mb-2 w-full rounded-lg border p-2 text-sm"><button class="w-full rounded-lg bg-rose-700 px-3 py-2 text-sm font-bold text-white">Hapus file poster</button></form></div></article>@empty<div class="p-8 text-center text-sm text-slate-500">Belum ada riwayat publikasi terverifikasi.</div>@endforelse</div></section>

    <section id="transactions" class="mt-7 overflow-hidden rounded-3xl bg-white shadow-sm"><div class="border-b p-5"><h2 class="text-xl font-extrabold text-slate-900">Riwayat transaksi publikasi</h2><p class="text-sm text-slate-500">Seluruh order, status pembayaran, paket, dan nominal.</p></div><div class="overflow-x-auto"><table class="w-full min-w-[850px] text-left text-sm"><thead class="bg-slate-50 text-xs uppercase text-slate-500"><tr><th class="p-4">Tanggal</th><th class="p-4">Penyelenggara</th><th class="p-4">Lomba</th><th class="p-4">Paket</th><th class="p-4">Nominal</th><th class="p-4">Pembayaran</th><th class="p-4">Bukti</th></tr></thead><tbody class="divide-y">@forelse($allOrders as $o)<tr><td class="p-4">{{ $o->created_at?->format('d/m/Y') }}</td><td class="p-4">{{ $o->user->name ?? '-' }}</td><td class="p-4 font-semibold">{{ $o->competition->title ?? '-' }}</td><td class="p-4">{{ $o->package }}</td><td class="p-4">Rp{{ number_format($o->amount,0,',','.') }}</td><td class="p-4"><span class="rounded-full bg-slate-100 px-2 py-1 text-xs font-bold">{{ strtoupper($o->payment_status) }}</span></td><td class="p-4">@if($o->proof_path)<a target="_blank" class="font-bold text-teal-700 underline" href="{{ asset('storage/'.$o->proof_path) }}">Lihat</a>@elseÃ¢â‚¬â€@endif</td></tr>@empty<tr><td colspan="7" class="p-8 text-center text-slate-500">Belum ada transaksi.</td></tr>@endforelse</tbody></table></div></section>

    <section id="audit" class="mt-7 overflow-hidden rounded-3xl bg-white shadow-sm"><div class="border-b p-5"><h2 class="text-xl font-extrabold text-slate-900">Jejak aktivitas admin</h2><p class="text-sm text-slate-500">Riwayat keputusan review, moderasi, dan perubahan masa tayang.</p></div><div class="divide-y">@forelse($audits as $a)<div class="flex flex-wrap justify-between gap-2 p-4"><div><p class="font-bold text-slate-800">{{ $a->description }}</p><p class="text-sm text-slate-500">{{ $a->action }} Ã‚Â· Order #{{ $a->publication_order_id }} Ã‚Â· User #{{ $a->user_id }}</p>@if($a->detail)<p class="text-sm text-slate-600">{{ $a->detail }}</p>@endif</div><time class="text-xs text-slate-400">{{ \Carbon\Carbon::parse($a->created_at)->format('d M Y H:i') }}</time></div>@empty<div class="p-8 text-center text-sm text-slate-500">Belum ada aktivitas tercatat sejak modul audit dipasang.</div>@endforelse</div></section>
</div></main>
@endsection

========================================
FILE: resources\views\organizer\dashboard.blade.php
========================================
@extends('layouts.app')

@section('title', 'Dashboard Penyelenggara')

@section('content')
<main class="min-h-screen bg-slate-50 py-10">
<div class="mx-auto max-w-6xl px-4">

    @if(session('success'))
        <div class="mb-6 rounded-xl border border-emerald-200 bg-emerald-50 p-4 text-sm font-semibold text-emerald-800">
            {{ session('success') }}
        </div>
    @endif

    @if($errors->any())
        <div class="mb-6 rounded-xl border border-red-200 bg-red-50 p-4 text-sm text-red-700">
            @foreach($errors->all() as $error)
                <p>{{ $error }}</p>
            @endforeach
        </div>
    @endif

    <div class="flex flex-wrap items-center justify-between gap-4">
        <div>
            <p class="text-sm font-bold text-ajara-red">RUANG PENYELENGGARA</p>
            <h1 class="mt-1 text-3xl font-extrabold text-ajara-teal">
                Dashboard Publikasi
            </h1>
            <p class="mt-2 text-slate-600">
                Kelola lomba, pembayaran, dan proses verifikasi.
            </p>
        </div>

        <div class="flex flex-wrap gap-2">
            <a href="{{ route('chat.index') }}" class="rounded-xl border border-teal-200 bg-white px-4 py-3 font-bold text-ajara-teal">Chat Admin</a>
            <a href="{{ route('notifications.index') }}" class="rounded-xl border border-slate-200 bg-white px-4 py-3 font-bold text-slate-700">Notifikasi</a>
            <a href="{{ route('organizer.create') }}" class="btn-primary rounded-xl px-5 py-3 font-bold text-white">+ Ajukan Lomba</a>
        </div>
    </div>

    <div class="mt-8 grid gap-4 sm:grid-cols-2 lg:grid-cols-4">

        @php
            $statistics = [
                ['Total Pengajuan', $orders->count()],
                ['Belum Bayar', $orders->where('payment_status','unpaid')->count()],
                ['Menunggu Verifikasi', $orders->where('payment_status','pending')->count()],
                ['Disetujui', $orders->where('payment_status','verified')->count()],
            ];
        @endphp

        @foreach($statistics as $statistic)

        <div class="rounded-2xl border border-slate-100 bg-white p-5 shadow-sm">
            <p class="text-sm font-medium text-slate-500">{{ $statistic[0] }}</p>
            <p class="mt-2 text-3xl font-extrabold text-ajara-teal">{{ $statistic[1] }}</p>
        </div>

        @endforeach

    </div>

    <section class="mt-8 overflow-hidden rounded-2xl bg-white shadow-sm">

        <div class="border-b p-5">
            <h2 class="text-lg font-extrabold text-ajara-teal">
                Riwayat Pengajuan Publikasi
            </h2>
            <p class="mt-1 text-sm text-slate-500">
                Pantau status pembayaran dan persetujuan Admin.
            </p>
        </div>

        <div class="divide-y">

            @forelse($orders as $o)

            <div class="flex flex-col justify-between gap-5 p-5 md:flex-row md:items-center">

                <div class="min-w-0">
                    <h3 class="font-bold text-slate-900">
                        {{ $o->competition->title }}
                    </h3>

                    <p class="mt-1 text-sm text-slate-600">
                        Paket {{ $o->package }}
                        Â· Rp{{ number_format($o->amount,0,',','.') }}
                    </p>

                    <p class="mt-2 text-sm">
                        Status pemeriksaan konten:

                        @if($o->content_review_status === 'approved')
                            <span class="font-bold text-emerald-700">Disetujui Admin</span>
                        @elseif($o->content_review_status === 'revision')
                            <span class="font-bold text-red-700">Perlu Revisi</span>
                        @else
                            <span class="font-bold text-amber-700">Menunggu Pemeriksaan</span>
                        @endif
                    </p>

                    @if($o->content_admin_note)
                        <div class="mt-3 rounded-lg bg-amber-50 p-3 text-sm text-amber-800">
                            <strong>Catatan Pemeriksaan Admin:</strong>
                            {{ $o->content_admin_note }}
                        </div>
                    @endif

                    <p class="mt-2 text-sm">
                        Status pembayaran:

                        @if($o->payment_status === 'verified')
                            <span class="font-bold text-emerald-700">Terverifikasi</span>
                        @elseif($o->payment_status === 'pending')
                            <span class="font-bold text-amber-700">Menunggu Admin</span>
                        @elseif($o->payment_status === 'rejected')
                            <span class="font-bold text-red-700">Ditolak</span>
                        @else
                            <span class="font-bold text-slate-600">Belum dibayar</span>
                        @endif
                    </p>

                    <p class="mt-1 text-sm text-slate-600">
                        Status publikasi:
                        <strong>{{ ucfirst($o->review_status) }}</strong>
                    </p>
                    @if($o->payment_status === 'verified' && $o->review_status === 'approved')
                        @php
                            $promotionActive = $o->promotion_started_at
                                && $o->promotion_ends_at
                                && now()->lt($o->promotion_ends_at);

                            $promotionExpired = $o->promotion_ends_at
                                && now()->gte($o->promotion_ends_at);

                            $remainingDays = $promotionActive
                                ? (int) ceil(now()->diffInHours($o->promotion_ends_at) / 24)
                                : 0;

                            $packageDays = [
                                'Basic' => 30,
                                'Premium' => 60,
                                'Featured' => 90,
                            ][$o->package] ?? 0;
                        @endphp

                        <div class="mt-4 rounded-xl border p-4
                            {{ $promotionActive ? 'border-teal-200 bg-teal-50' : 'border-slate-200 bg-slate-50' }}">

                            <div class="flex flex-wrap items-center justify-between gap-2">
                                <strong class="text-sm text-ajara-teal">
                                    Masa Promosi {{ $o->package }}
                                </strong>

                                @if($promotionActive)
                                    @if($remainingDays <= 7)
                                        <span class="rounded-full bg-amber-100 px-3 py-1 text-xs font-bold text-amber-800">
                                            Segera Berakhir
                                        </span>
                                    @else
                                        <span class="rounded-full bg-emerald-100 px-3 py-1 text-xs font-bold text-emerald-800">
                                            Promosi Aktif
                                        </span>
                                    @endif
                                @elseif($promotionExpired)
                                    <span class="rounded-full bg-red-100 px-3 py-1 text-xs font-bold text-red-700">
                                        Promosi Berakhir
                                    </span>
                                @else
                                    <span class="rounded-full bg-slate-200 px-3 py-1 text-xs font-bold text-slate-700">
                                        Belum Diaktifkan
                                    </span>
                                @endif
                            </div>

                            @if($promotionActive)
                                <p class="mt-3 text-2xl font-extrabold text-ajara-teal">
                                    {{ $remainingDays }} hari
                                </p>

                                <p class="text-xs text-slate-500">
                                    Sisa masa promosi
                                </p>

                                <div class="mt-3 grid grid-cols-2 gap-3">
                                    <div class="rounded-lg bg-white p-3">
                                        <p class="text-xs text-slate-500">Mulai</p>
                                        <p class="mt-1 text-sm font-bold text-slate-800">
                                            {{ $o->promotion_started_at->translatedFormat('d M Y') }}
                                        </p>
                                    </div>

                                    <div class="rounded-lg bg-white p-3">
                                        <p class="text-xs text-slate-500">Berakhir</p>
                                        <p class="mt-1 text-sm font-bold text-slate-800">
                                            {{ $o->promotion_ends_at->translatedFormat('d M Y') }}
                                        </p>
                                    </div>
                                </div>

                            @elseif($promotionExpired)
                                <p class="mt-3 text-sm text-slate-600">
                                    Masa promosi berakhir pada
                                    <strong>{{ $o->promotion_ends_at->translatedFormat('d M Y') }}</strong>.
                                </p>
                            @else
                                <p class="mt-3 text-sm text-slate-600">
                                    Tanggal promosi belum tersedia. Silakan hubungi Admin AJARA.
                                </p>
                            @endif
                        </div>
                    @endif

                    @if($o->admin_note)
                        <div class="mt-3 rounded-lg bg-red-50 p-3 text-sm text-red-800">
                            <strong>Catatan Admin:</strong>
                            {{ $o->admin_note }}
                        </div>
                    @endif
                </div>


<div class="flex flex-wrap gap-2">

    <a href="{{ route('organizer.payment.receipt',$o) }}"
       class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-bold text-ajara-teal hover:bg-slate-50">
        Lihat Struk
    </a>

    @if($o->competition->status === 'closed')
        <span class="rounded-xl bg-slate-200 px-4 py-2 text-sm font-bold text-slate-700">
            Lomba Ditutup
        </span>

    @elseif($o->content_review_status === 'revision')
        <a href="{{ route('organizer.edit', $o) }}"
           class="rounded-xl bg-amber-600 px-4 py-2 text-sm font-bold text-white hover:opacity-90">
            Perbaiki Pengajuan
        </a>

    @elseif($o->content_review_status === 'pending')
        <span class="rounded-xl bg-amber-100 px-4 py-2 text-sm font-bold text-amber-800">
            Menunggu Pemeriksaan Konten
        </span>

    @elseif($o->content_review_status === 'approved' && in_array($o->payment_status, ['unpaid','rejected']))
        <a href="{{ route('organizer.payment', $o) }}"
           class="rounded-xl bg-ajara-teal px-4 py-2 text-sm font-bold text-white hover:opacity-90">
            Bayar Sekarang
        </a>

    @elseif($o->payment_status === 'pending')
        <span class="rounded-xl bg-amber-100 px-4 py-2 text-sm font-bold text-amber-800">
            Menunggu Verifikasi Pembayaran
        </span>

    @elseif($o->payment_status === 'verified')
        <span class="rounded-xl bg-emerald-100 px-4 py-2 text-sm font-bold text-emerald-800">
            Lomba Dipublikasikan
        </span>

        @if(
            $o->review_status === 'approved'
            && $o->competition->status === 'published'
            && $o->promotion_started_at
            && $o->promotion_ends_at
            && now()->lt($o->promotion_ends_at)
)
            <a href="{{ route('organizer.manage', $o) }}"
               class="rounded-xl bg-ajara-teal px-4 py-2 text-sm font-bold text-white hover:opacity-90">
                Kelola Lomba
            </a>

            <form method="POST"
                  action="{{ route('organizer.close', $o) }}"
                  onsubmit="return confirm('Yakin ingin menutup lomba ini? Mahasiswa tidak dapat mendaftar lagi setelah lomba ditutup.');">
                @csrf
                <button type="submit"
                        class="rounded-xl bg-red-600 px-4 py-2 text-sm font-bold text-white hover:bg-red-700">
                    Tutup Lomba
                </button>
            </form>

        @endif
        @endif

</div>

</div>

            @empty

            <div class="p-12 text-center">
                <p class="text-lg font-bold text-slate-700">
                    Belum ada pengajuan lomba.
                </p>
                <p class="mt-2 text-sm text-slate-500">
                    Mulai publikasikan lombamu melalui AJARA.
                </p>
                <a href="{{ route('organizer.create') }}"
                   class="mt-5 inline-block rounded-xl bg-ajara-teal px-5 py-3 font-bold text-white">
                    Buat Pengajuan
                </a>
            </div>

            @endforelse

        </div>
    </section>
</div>
</main>
@endsection


========================================
FILE: resources\views\chat\index.blade.php
========================================
@extends('layouts.app')
@section('title', 'Chat AJARA')
@section('content')
<main class="min-h-screen bg-gradient-to-br from-slate-50 via-cyan-50 to-white py-8">
<div class="mx-auto max-w-6xl px-4">
    @if(session('success'))<div class="mb-4 rounded-xl bg-emerald-50 p-4 font-semibold text-emerald-800">{{ session('success') }}</div>@endif
    <section class="overflow-hidden rounded-3xl border border-slate-100 bg-white shadow-xl shadow-slate-200/60">
        <header class="bg-gradient-to-r from-[#064e55] to-[#0e7490] p-6 text-white"><p class="text-xs font-black tracking-[.25em] text-cyan-100">AJARA CONNECT</p><h1 class="mt-2 text-2xl font-black">Pusat komunikasi</h1><p class="mt-1 text-sm text-cyan-50">Percakapan langsung Admin dan penyelenggara.</p></header>
        <div class="grid min-h-[480px] md:grid-cols-[280px_1fr]">
            @if($isAdmin)
            <aside class="border-b bg-slate-50 p-4 md:border-b-0 md:border-r"><h2 class="mb-3 font-extrabold text-slate-800">Daftar penyelenggara</h2>
                @forelse($users as $u)<a href="{{ route('chat.index',['user'=>$u->id]) }}" class="mb-2 flex items-center justify-between rounded-xl p-3 text-sm {{ $selectedUser && $selectedUser->id === $u->id ? 'bg-teal-100 font-bold text-teal-900' : 'bg-white text-slate-700 hover:bg-slate-100' }}"><span>{{ $u->name }}</span><span class="text-xs text-slate-400">{{ $u->chat_messages_count }}</span></a>@empty<p class="text-sm text-slate-500">Belum ada akun penyelenggara.</p>@endforelse
            </aside>
            @endif
            <section class="flex min-w-0 flex-col">
                @if($selectedUser)
                    <div class="border-b p-4"><p class="font-bold text-slate-900">{{ $isAdmin ? 'Chat dengan '.$selectedUser->name : 'Chat dengan Admin AJARA' }}</p><p class="text-xs text-slate-500">Pesan tersimpan dalam riwayat akun.</p></div>
                    <div class="flex-1 space-y-3 overflow-y-auto bg-slate-50/70 p-5">
                        @forelse($messages as $m)<div class="flex {{ $m->sender_role === 'admin' ? 'justify-end' : 'justify-start' }}"><div class="max-w-[85%] rounded-2xl px-4 py-3 shadow-sm {{ $m->sender_role === 'admin' ? 'bg-teal-800 text-white' : 'border bg-white text-slate-800' }}"><p class="whitespace-pre-wrap text-sm">{{ $m->message }}</p><p class="mt-1 text-right text-[10px] opacity-60">{{ $m->created_at->format('d M Y H:i') }}</p></div></div>@empty<div class="grid h-48 place-items-center text-sm text-slate-400">Mulai percakapan AJARA di sini.</div>@endforelse
                    </div>
                    <form method="POST" action="{{ route('chat.store') }}" class="flex gap-2 border-t bg-white p-4">@csrf @if($isAdmin)<input type="hidden" name="user_id" value="{{ $selectedUser->id }}">@endif<input name="message" required maxlength="3000" placeholder="Tulis pesan..." class="min-w-0 flex-1 rounded-xl border border-slate-200 px-4 py-3 text-sm text-slate-900 focus:border-teal-600 focus:outline-none"><button class="rounded-xl bg-teal-800 px-5 font-bold text-white hover:bg-teal-900">Kirim</button></form>
                @else<div class="grid flex-1 place-items-center p-8 text-center text-slate-500">Pilih penyelenggara untuk memulai percakapan.</div>@endif
            </section>
        </div>
    </section>
</div></main>
@endsection