Merge branch 'feature/admin-panel'

This commit is contained in:
kusowl 2026-01-29 09:48:25 +05:30
commit a8be44553e
8 changed files with 114 additions and 62 deletions

View File

@ -0,0 +1,49 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\Deal;
use Illuminate\Support\Facades\Log;
class DealController extends Controller
{
public function index()
{
return view('dashboards.admin.deals.index')
->with('deals', $this->deals());
}
public function approve(Deal $deal)
{
try {
\DB::transaction(function () use ($deal) {
$deal->active = true;
$deal->save();
});
return back()->with('success', 'Deal activated successfully.');
} catch (\Throwable $e) {
Log::error('Deal activation Failed: ', [$e->getMessage(), $e->getTrace()]);
return back()->with('error', 'Something went wrong.');
}
}
public function reject(Deal $deal){
try {
$deal->delete();
return back()->with('success', 'Deal deleted successfully.');
} catch (\Throwable $e) {
Log::error('Deal deletion Failed: ', [$e->getMessage(), $e->getTrace()]);
return back()->with('error', 'Something went wrong.');
}
}
private function deals()
{
return Deal::where('active', false)->get();
}
}

View File

@ -31,6 +31,7 @@ public function __invoke(
protected function deals(FormRequest $request, Builder $query, AddRecentSearchAction $action): LengthAwarePaginator
{
$query->tap(fn ($q) => (new Deal)->withActiveDeals($q));
// Add a search query
if ($request->has('search') && $request->get('search') !== null) {
$query->tap(fn ($q) => (new Deal)->search($q, $request->search));

View File

@ -25,8 +25,7 @@ public function builder(): Builder
->with('type');
},
])
// Select only admin-approved deals
->tap(fn ($q) => (new Deal)->withActiveDeals($q))
// Check if the current user interacted with the deal
->tap(fn ($q) => (new Deal)->withCurrentUserInteractions($q))
->tap(fn ($q) => (new Deal)->withLikePerDeal($q))

View File

@ -0,0 +1,12 @@
import {showDealModal} from "./deal-view-modal.js";
const table = document.querySelector('.ui-table')
if (table) {
const btns = table.querySelectorAll('.view-deal-btn');
btns.forEach(btn => {
btn.addEventListener('click', async () => {
let dealId = btn.dataset.dealId;
await showDealModal(dealId)
})
})
}

View File

@ -37,6 +37,11 @@ class="flex flex-col p-4 pt-6 justify-between font-medium h-full w-full overflow
<x-heroicon-o-exclamation-triangle class="w-5 min-w-5"/>
<p class="sidebar-text transition-opacity duration-300 ease-in-out">Manage Reports</p>
</x-dashboard.broker.sidebar.item>
<x-dashboard.broker.sidebar.item :link="route('admin.deals.index')">
<x-heroicon-o-fire class="w-5 min-w-5"/>
<p class="sidebar-text transition-opacity duration-300 ease-in-out">Manage Deals</p>
</x-dashboard.broker.sidebar.item>
</div>
</div>

View File

@ -1,78 +1,53 @@
@php use App\Enums\ReportStatus; @endphp
<x-dashboard.admin.layout title="Deals">
<x-dashboard.admin.layout title="Manage Deals">
<x-slot:heading>
<x-dashboard.page-heading
title="Manage Customers"
description="Edit, Delete and Login as Customer"
title="Manage Deals"
description="Approve or reject deals"
/>
</x-slot:heading>
<div class="flex items-center justify-center px-4 pb-4 pt-0 md:px-8 md:pb-8">
<x-dashboard.card class="w-full">
<h3 class="text-md font-bold mb-2">Reported deals</h3>
<h4 class="text-sm font-medium mb-4 text-accent-600">Total Reports: {{$reports->count()}}</h4>
<h3 class="text-md font-bold mb-2">Approve deals</h3>
<x-ui.table>
<x-ui.table.head>
<th>Type</th>
<th>Title</th>
<th>Description</th>
<th>Customer</th>
<th>Status</th>
<th class="flex w-full justify-center items-center">
Deal
<x-heroicon-o-arrow-top-right-on-square class="w-4 ml-1"/>
</th>
<th>Link</th>
<th>Category</th>
<th>Broker</th>
</x-ui.table.head>
@forelse($reports as $report)
@forelse($deals as $deal)
<x-ui.table.row>
<td class="text-sm font-medium px-4 text-center">{{ucfirst($report->type->value)}}</td>
<td class="text-sm text-accent-600 px-4 text-center max-w-40">{{$report->description}}</td>
<td class="text-sm px-4 text-center">{{$report->user->name}}</td>
<td class="text-center px-4">
<x-ui.badge
:title="$report->status->value"
:variant="match ($report->status){
ReportStatus::Resolved => 'green',
ReportStatus::Pending => 'yellow',
ReportStatus::Rejected => 'red'
}"
/>
</td>
<td class="text-sm px-4 text-center truncate max-w-40">
<a target="_blank" class="hover:underline"
href="{{route('explore', ['show' => $report->deals()->first()->id])}}">
{{$report->deals()->first()->title}}
</a>
</td>
<td class="text-sm font-medium px-4 text-center truncate max-w-20">{{ucfirst($deal->title)}}</td>
<td class="text-sm text-accent-600 px-4 text-center truncate max-w-60">{{$deal->description}}</td>
<td class="text-sm px-4 text-center">{{$deal->link}}</td>
<td class="text-sm px-4 text-center">{{$deal->category->name}}</td>
<td class="text-sm px-4 text-center">{{$deal->broker->name}}</td>
<x-slot:actions>
<div class="flex items-center justify-center space-x-2 py-1 px-2">
@if($report->status !== ReportStatus::Resolved)
<form action="{{route('admin.reports.resolve', $report)}}"
onsubmit="return confirm('Are you sure to mark this resolve ?')" method="post"
<form action="{{route('admin.deals.approve', $deal)}}"
onsubmit="return confirm('Are you sure to activate the deal ?')" method="post"
class=" h-full items-center flex justify-center">
@csrf
<x-ui.button-sm tooltip="Mark resolved" variant="green">
<x-ui.button-sm tooltip="Approve deal" variant="green">
<x-heroicon-o-check class="w-4"/>
</x-ui.button-sm>
</form>
@endif
@if($report->status !== ReportStatus::Rejected)
<form action="{{route('admin.reports.reject', $report)}}"
onsubmit="return confirm('Are you sure to reject this ?')" method="post"
<form action="{{route('admin.deals.reject', $deal)}}"
onsubmit="return confirm('Are you sure to delete the deal ?')" method="post"
class=" h-full items-center flex justify-center">
@csrf
<x-ui.button-sm tooltip="Reject" variant="red">
<x-ui.button-sm tooltip="Delete deal" variant="red">
<x-heroicon-o-x-mark class="w-4"/>
</x-ui.button-sm>
</form>
@endif
<form action="{{route('admin.reports.remove-content', $report)}}"
onsubmit="return confirm('Are you sure to remove the deal ?')" method="post"
class=" h-full items-center flex justify-center">
@csrf
<x-ui.button-sm tooltip="Remove Content" variant="ghost">
<x-heroicon-o-exclamation-triangle class="w-4"/>
<x-ui.button-sm data-deal-id="{{$deal->id}}" class="view-deal-btn" tooltip="View Content" variant="ghost">
<x-heroicon-o-eye class="w-4"/>
</x-ui.button-sm>
</form>
</div>
</x-slot:actions>
</x-ui.table.row>
@ -84,4 +59,6 @@ class=" h-full items-center flex justify-center">
</x-ui.table>
</x-dashboard.card>
</div>
<x-dashboard.user.deal-modal />
@vite('resources/js/admin-deals.js')
</x-dashboard.admin.layout>

View File

@ -5,10 +5,14 @@
use App\Queries\ExplorePageDealsQuery;
Route::get('/deals/{deal}', function (Deal $deal) {
$query = (new ExplorePageDealsQuery)->builder();
if (! Auth::user()->isAdmin()) {
$query // Select only admin-approved deals
->tap(fn ($q) => (new Deal)->withActiveDeals($q));
}
$query->where('id', $deal->id);
return new DealResource(
(new ExplorePageDealsQuery)
->builder()
->where('id', $deal->id)
->first()
$query->first()
);
});

View File

@ -4,6 +4,7 @@
use App\Http\Controllers\Admin\AdminDashboardController;
use App\Http\Controllers\Admin\BrokerController;
use App\Http\Controllers\Admin\CustomerController;
use App\Http\Controllers\Admin\DealController;
use App\Http\Controllers\Admin\ReportController;
use App\Http\Middleware\HasRole;
@ -22,4 +23,8 @@
Route::post('/reports/reject/{report}', [ReportController::class, 'reject'])->name('reports.reject');
Route::post('/reports/remove/{report}',
[ReportController::class, 'removeContent'])->name('reports.remove-content');
Route::get('/deals', [DealController::class, 'index'])->name('deals.index');
Route::post('/deals/approve/{deal}', [DealController::class, 'approve'])->name('deals.approve');
Route::post('/deals/reject/{deal}', [DealController::class, 'reject'])->name('deals.reject');
});