feature (favorite and reported deals):
- add favorites and reported tabs in user profile pages - add remove favorites - customers can view a deal directly from profiles section and deal modal is shown in explore page - fix formatting by pint
This commit is contained in:
parent
a5f2f43fb1
commit
94ef8f360d
@ -1,4 +1,4 @@
|
||||
APP_NAME=Laravel
|
||||
APP_NAME=DealHub
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
|
||||
20
app/Actions/GetUserFavoritesAction.php
Normal file
20
app/Actions/GetUserFavoritesAction.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions;
|
||||
|
||||
use App\Enums\InteractionType;
|
||||
use App\Models\Deal;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
final readonly class GetUserFavoritesAction
|
||||
{
|
||||
public function execute(User $user): Collection
|
||||
{
|
||||
return $user->interactedDeals()
|
||||
->where('interactions.type', InteractionType::Favorite)
|
||||
->tap(fn ($q) => (new Deal)->withActiveDeals($q))
|
||||
->select('deals.id', 'deals.title')
|
||||
->get();
|
||||
}
|
||||
}
|
||||
17
app/Actions/GetUserReportedDealsAction.php
Normal file
17
app/Actions/GetUserReportedDealsAction.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
final readonly class GetUserReportedDealsAction
|
||||
{
|
||||
public function execute(User $user): Collection
|
||||
{
|
||||
return $user->reports()
|
||||
->select('reports.id')
|
||||
->with('deals:id,title')
|
||||
->get();
|
||||
}
|
||||
}
|
||||
@ -25,22 +25,22 @@ public function store(StoreRegisterdUser $request)
|
||||
DB::transaction(function () use ($data) {
|
||||
switch ($data['role']) {
|
||||
case UserTypes::Broker->value:
|
||||
{
|
||||
|
||||
$data['status'] = UserStatus::Pending->value;
|
||||
|
||||
// Create Broker first, then link the user
|
||||
$broker = Broker::create();
|
||||
$broker->user()->create($data);
|
||||
break;
|
||||
}
|
||||
|
||||
case UserTypes::User->value:
|
||||
{
|
||||
|
||||
$data['status'] = UserStatus::Active->value;
|
||||
|
||||
$customer = Customer::create();
|
||||
$customer->user()->create($data);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -9,7 +9,6 @@
|
||||
use App\Services\ProfileInitialsService;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class BrokerProfileController extends Controller
|
||||
{
|
||||
|
||||
@ -33,7 +33,7 @@ protected function deals(FormRequest $request, Builder $query, AddRecentSearchAc
|
||||
{
|
||||
// Add a search query
|
||||
if ($request->has('search') && $request->get('search') !== null) {
|
||||
$query->tap(fn($q) => (new Deal)->search($q, $request->search));
|
||||
$query->tap(fn ($q) => (new Deal)->search($q, $request->search));
|
||||
|
||||
\Illuminate\Support\defer(function () use ($action, $request) {
|
||||
$action->execute($request->user(), ['query' => $request->search]);
|
||||
@ -42,7 +42,7 @@ protected function deals(FormRequest $request, Builder $query, AddRecentSearchAc
|
||||
|
||||
// Add category sorting filter
|
||||
if ($request->has('category') && $request->get('category') !== null) {
|
||||
$query->tap(fn($q) => (new Deal)->filterByCategory($q, $request->category));
|
||||
$query->tap(fn ($q) => (new Deal)->filterByCategory($q, $request->category));
|
||||
}
|
||||
|
||||
// Add sorting filters
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Deal;
|
||||
use App\Models\Interaction;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
@ -15,9 +16,8 @@ class InteractionController extends Controller
|
||||
* Interact to a deal by Like or Favorite state
|
||||
*
|
||||
* @param InteractionType $type [InteractionType::Like, InteractionType::Favorite]
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function togglesState(Deal $deal, InteractionType $type)
|
||||
public function togglesState(Deal $deal, InteractionType $type, Request $request)
|
||||
{
|
||||
if (! in_array($type, [InteractionType::Like, InteractionType::Favorite])) {
|
||||
return response()->json(['error' => 'This interaction is not supported'], 400);
|
||||
@ -47,8 +47,11 @@ public function togglesState(Deal $deal, InteractionType $type)
|
||||
|
||||
$message = ucfirst($type->value).' added to deal';
|
||||
}
|
||||
|
||||
return response()->json(['message' => $message]);
|
||||
if ($request->expectsJson()) {
|
||||
return response()->json(['message' => $message]);
|
||||
} else {
|
||||
return back()->with('success', $message);
|
||||
}
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Error when liked a deal',
|
||||
@ -60,8 +63,11 @@ public function togglesState(Deal $deal, InteractionType $type)
|
||||
'trace' => $e->getTraceAsString(),
|
||||
]
|
||||
);
|
||||
if ($request->expectsJson()) {
|
||||
return response()->json(['error' => 'Something went wrong.'], 500);
|
||||
}
|
||||
|
||||
return response()->json(['error' => 'Something went wrong.'], 500);
|
||||
return back()->with('error', 'Something went wrong.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -78,6 +78,21 @@ public function update(Request $request, Report $report)
|
||||
*/
|
||||
public function destroy(Report $report)
|
||||
{
|
||||
//
|
||||
try {
|
||||
DB::transaction(function () use ($report) {
|
||||
$report->deals()->detach();
|
||||
$report->delete();
|
||||
});
|
||||
|
||||
return back()->with('success', 'Report deleted successfully.');
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Error deleting report', [
|
||||
'user_id' => Auth::id(),
|
||||
'report_id' => $report->id,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
|
||||
return back()->with('error', 'Something went wrong.');
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,13 +2,12 @@
|
||||
|
||||
namespace App\Http\Controllers\User;
|
||||
|
||||
use App\Actions\GetUserFavoritesAction;
|
||||
use App\Actions\GetUserReportedDealsAction;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\StoreBrokerProfileRequest;
|
||||
use App\Http\Requests\StoreCustomerProfileRequest;
|
||||
use App\Models\Broker;
|
||||
use App\Models\User;
|
||||
use App\Services\ProfileInitialsService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
@ -17,8 +16,12 @@ class UserProfileController extends Controller
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(User $profile, ProfileInitialsService $service)
|
||||
{
|
||||
public function show(
|
||||
User $profile,
|
||||
ProfileInitialsService $service,
|
||||
GetUserFavoritesAction $favoritesAction,
|
||||
GetUserReportedDealsAction $reportedDealsAction
|
||||
) {
|
||||
// Get the user profile
|
||||
$user = $profile->type;
|
||||
|
||||
@ -32,7 +35,9 @@ public function show(User $profile, ProfileInitialsService $service)
|
||||
->with('initials', $initials)
|
||||
->with('location', $user->location)
|
||||
->with('bio', $user->bio)
|
||||
->with('phone', $user->phone);
|
||||
->with('phone', $user->phone)
|
||||
->with('favorites', $favoritesAction->execute($profile))
|
||||
->with('reported', $reportedDealsAction->execute($profile));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
class Customer extends Model
|
||||
{
|
||||
protected $fillable = ['bio', 'location', 'phone'];
|
||||
|
||||
public function user(): MorphOne
|
||||
{
|
||||
return $this->morphOne(User::class, 'role');
|
||||
|
||||
@ -118,5 +118,4 @@ public function filterByCategory(Builder $query, string $category): Builder
|
||||
{
|
||||
return $query->where('deal_category_id', $category);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -89,4 +89,14 @@ public function dealsInteractions(): HasManyThrough
|
||||
{
|
||||
return $this->hasManyThrough(Interaction::class, Deal::class);
|
||||
}
|
||||
|
||||
public function interactedDeals(): HasManyThrough
|
||||
{
|
||||
return $this->hasManyThrough(Deal::class, Interaction::class, 'user_id', 'id', 'id', 'deal_id');
|
||||
}
|
||||
|
||||
public function reports(): HasMany
|
||||
{
|
||||
return $this->hasMany(Report::class);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
|
||||
class ProfileInitialsService
|
||||
{
|
||||
|
||||
/**
|
||||
* Create the initials from a full name (e.g. John Doe, Alex Mark, jane clerk)
|
||||
* to display on the profile page (e.g. JD, AM, JC).
|
||||
@ -15,7 +14,7 @@ public function create(string $fullname)
|
||||
{
|
||||
return Str::of($fullname)
|
||||
->explode(' ')
|
||||
->map(fn($word) => Str::substr(ucfirst($word), 0, 1))
|
||||
->map(fn ($word) => Str::substr(ucfirst($word), 0, 1))
|
||||
->join('');
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,8 @@
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
|
||||
@ -9,13 +9,15 @@ import "./toast.js"
|
||||
import "./deal-view-modal.js"
|
||||
import {favorite, like, redirect} from "./interaction.js";
|
||||
import {showReportModal} from "./report-deal.js";
|
||||
import {initTabs} from "./tab.js";
|
||||
import {loadModalFromQuery} from "./explore-page.js";
|
||||
|
||||
document.like = like;
|
||||
document.favorite = favorite;
|
||||
document.redirect = redirect;
|
||||
document.showReportModal = showReportModal;
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
window.addEventListener('load', async () => {
|
||||
const preloader = document.getElementById('preloader');
|
||||
const content = document.getElementById('content');
|
||||
|
||||
@ -32,4 +34,8 @@ window.addEventListener('load', () => {
|
||||
if (savedState) {
|
||||
setSidebarState(savedState);
|
||||
}
|
||||
|
||||
initTabs();
|
||||
|
||||
await loadModalFromQuery();
|
||||
});
|
||||
|
||||
3
resources/js/bootstrap.js
vendored
3
resources/js/bootstrap.js
vendored
@ -1,4 +1,7 @@
|
||||
import axios from 'axios';
|
||||
|
||||
window.axios = axios;
|
||||
|
||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
window.axios.defaults.headers.common['Accept'] = 'application/json';
|
||||
window.axios.defaults.headers.common['Content-Type'] = 'application/json';
|
||||
|
||||
@ -3,7 +3,7 @@ import {closeModal, showModal} from "@/modal.js";
|
||||
import {redirect} from "./interaction.js";
|
||||
import {toggleShimmer} from "./shimmer.js";
|
||||
|
||||
async function showDealModal(dealId) {
|
||||
export async function showDealModal(dealId) {
|
||||
if (!dealId) {
|
||||
showToast('Something went wrong!');
|
||||
return;
|
||||
|
||||
11
resources/js/explore-page.js
Normal file
11
resources/js/explore-page.js
Normal file
@ -0,0 +1,11 @@
|
||||
import {showDealModal} from "./deal-view-modal.js";
|
||||
|
||||
export async function loadModalFromQuery(){
|
||||
const query = new URLSearchParams(window.location.search);
|
||||
if (query.has('show')) {
|
||||
const dealId = query.get('show');
|
||||
if(dealId){
|
||||
await showDealModal(dealId);
|
||||
}
|
||||
}
|
||||
}
|
||||
32
resources/js/tab.js
Normal file
32
resources/js/tab.js
Normal file
@ -0,0 +1,32 @@
|
||||
export function initTabs() {
|
||||
try {
|
||||
const tabs = document.querySelectorAll('.tabs');
|
||||
tabs.forEach(tab => {
|
||||
const tabBtns = tab.querySelectorAll('.tab-btn');
|
||||
tabBtns.forEach(tabBtn =>
|
||||
tabBtn.addEventListener('click', (e) => {
|
||||
// Make the current button active
|
||||
tabBtns.forEach(btn => btn.classList.remove('bg-white'));
|
||||
tabBtn.classList.add('bg-white');
|
||||
|
||||
// Hide all other tabs
|
||||
const tabContents = tab.querySelectorAll('.tab-content');
|
||||
tabContents.forEach(content => content.removeAttribute('data-show'));
|
||||
|
||||
// Show the target tab
|
||||
const targetContent = tabBtn.dataset.target;
|
||||
if (targetContent) {
|
||||
const contentTabData = `[data-tab="${targetContent}"]`;
|
||||
const tabContent = tab.querySelector(contentTabData);
|
||||
if (tabContent) {
|
||||
tabContent.setAttribute('data-show', '')
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
@ -2,9 +2,9 @@
|
||||
<div class="p-4 text-sm bg-gray-100 border-gray-200 border rounded-xl">
|
||||
<p class="font-bold mb-2">Broker Contact</p>
|
||||
<div class="text-accent-600 space-y-1">
|
||||
<p data-is-loading="true" class="broker-name">{{$broker->name ?? ''}}</p>
|
||||
<p data-is-loading="true" class="broker-email">{{$broker->email ?? ''}}</p>
|
||||
<p data-is-loading="true" class="broker-phone">{{$broker->role->phone ?? ''}}</p>
|
||||
<p data-is-loading="false" class="broker-name">{{$broker->name ?? ''}}</p>
|
||||
<p data-is-loading="false" class="broker-email">{{$broker->email ?? ''}}</p>
|
||||
<p data-is-loading="false" class="broker-phone">{{$broker->role->phone ?? ''}}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@props(['deals' => []])
|
||||
@props(['deals' => [], 'isInteractive'])
|
||||
<div class="grid md:grid-cols-2 gap-6">
|
||||
@forelse($deals as $deal)
|
||||
<x-dashboard.user.listing-card :deal="$deal" :broker="$deal->broker"/>
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
$variants = [
|
||||
'neutral' => 'bg-primary-600 text-white',
|
||||
'ghost' => 'bg-gray-100 text-black text-sm',
|
||||
'red' => 'bg-red-500 text-red-100 text-sm'
|
||||
];
|
||||
|
||||
$variantClass = $variants[$variant] ?? '';
|
||||
|
||||
4
resources/views/components/ui/tab/button.blade.php
Normal file
4
resources/views/components/ui/tab/button.blade.php
Normal file
@ -0,0 +1,4 @@
|
||||
@props(['active' => false])
|
||||
<x-ui.toggle-button :active="$active" {{$attributes->merge(['class' => 'tab-btn'])}}>
|
||||
{{$slot}}
|
||||
</x-ui.toggle-button>
|
||||
3
resources/views/components/ui/tab/content.blade.php
Normal file
3
resources/views/components/ui/tab/content.blade.php
Normal file
@ -0,0 +1,3 @@
|
||||
<div {{$attributes->merge(['class' => 'tab-content [&:not([data-show])]:hidden'])}}>
|
||||
{{$slot}}
|
||||
</div>
|
||||
8
resources/views/components/ui/tab/index.blade.php
Normal file
8
resources/views/components/ui/tab/index.blade.php
Normal file
@ -0,0 +1,8 @@
|
||||
<div {{$attributes->merge(['class' => 'tabs'])}} >
|
||||
<x-ui.toggle-button-group class="flex-row">
|
||||
{{$buttons ?? ''}}
|
||||
</x-ui.toggle-button-group>
|
||||
<div class="w-full">
|
||||
{{$slot}}
|
||||
</div>
|
||||
</div>
|
||||
3
resources/views/components/ui/table/head.blade.php
Normal file
3
resources/views/components/ui/table/head.blade.php
Normal file
@ -0,0 +1,3 @@
|
||||
<tr class="font-bold">
|
||||
{{$slot}}
|
||||
</tr>
|
||||
6
resources/views/components/ui/table/index.blade.php
Normal file
6
resources/views/components/ui/table/index.blade.php
Normal file
@ -0,0 +1,6 @@
|
||||
<div class="pt-2 rounded-lg border border-gray-200">
|
||||
<table class="table-auto w-full ">
|
||||
{{$slot}}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
8
resources/views/components/ui/table/row.blade.php
Normal file
8
resources/views/components/ui/table/row.blade.php
Normal file
@ -0,0 +1,8 @@
|
||||
<tr class=" border-t border-t-gray-200 ">
|
||||
{{$slot}}
|
||||
@if(($actions ?? '') !== '')
|
||||
<td class="border-l border-l-gray-200">
|
||||
{{$actions ?? ''}}
|
||||
</td>
|
||||
@endif
|
||||
</tr>
|
||||
@ -1,8 +1,7 @@
|
||||
@props(['active' => false])
|
||||
@aware(['activeColor' => 'bg-white'])
|
||||
<div
|
||||
{{$attributes}}
|
||||
{{$attributes->class(["rounded-full hover:bg-gray-100 hover:border-gray-300 border border-transparent transition-colors duration-300 ease-in-out", $activeColor => $active])}}
|
||||
{{$attributes->class(["rounded-full hover:border-gray-300 border border-transparent transition-colors duration-300 ease-in-out", $activeColor => $active])}}
|
||||
>
|
||||
{{ $slot }}
|
||||
</div>
|
||||
|
||||
@ -15,7 +15,23 @@ class="border border-accent-600/40">
|
||||
</x-slot:end>
|
||||
</x-dashboard.page-heading>
|
||||
|
||||
<div class="flex items-center justify-center mt-4 md:mt-8 px-4 pb-4 pt-0 md:px-8 md:pb-8">
|
||||
@session('error')
|
||||
<div class="m-4">
|
||||
<x-ui.alert variant="error">
|
||||
{{$value}}
|
||||
</x-ui.alert>
|
||||
</div>
|
||||
@endsession
|
||||
|
||||
@session('success')
|
||||
<div class="m-8">
|
||||
<x-ui.alert variant="success">
|
||||
{{$value}}
|
||||
</x-ui.alert>
|
||||
</div>
|
||||
@endsession
|
||||
|
||||
<div class="flex flex-col space-y-8 items-center justify-center mt-4 md:mt-8 px-4 pb-4 pt-0 md:px-8 md:pb-8">
|
||||
<div class="flex items-center justify-center w-full">
|
||||
<x-dashboard.card class="w-full">
|
||||
<div class="grid grid-cols-8 gap-6">
|
||||
@ -60,5 +76,82 @@ class="w-25 h-25 rounded-xl bg-linear-150 from-[#305afc] to-[#941dfb] text-5xl t
|
||||
</div>
|
||||
</x-dashboard.card>
|
||||
</div>
|
||||
<x-ui.tab class="self-start w-full">
|
||||
<x-slot:buttons>
|
||||
<x-ui.tab.button :active="true" data-target="favorites">
|
||||
<div class="flex items-center cursor-default px-2 py-1 space-x-2">
|
||||
<x-heroicon-o-heart class="w-4 stroke-2"/>
|
||||
<p class="font-bold text-xs sm:text-sm md:text-md">Favorites</p>
|
||||
</div>
|
||||
</x-ui.tab.button>
|
||||
<x-ui.tab.button data-target="reports">
|
||||
<div class="flex items-center cursor-default px-2 py-1 space-x-2">
|
||||
<x-heroicon-o-exclamation-triangle class="w-4 stroke-2"/>
|
||||
<p class="font-bold text-xs sm:text-sm md:text-md">Reported Deals</p>
|
||||
</div>
|
||||
</x-ui.tab.button>
|
||||
</x-slot:buttons>
|
||||
|
||||
<x-ui.tab.content data-show data-tab="favorites" class="w-full">
|
||||
<x-dashboard.card class="bg-white mt-8">
|
||||
<p class="font-bold mb-6">Your favorite deals</p>
|
||||
<x-ui.table>
|
||||
<x-ui.table.head>
|
||||
<th colspan="2" class="pb-2">Deals</th>
|
||||
</x-ui.table.head>
|
||||
@forelse($favorites as $deal)
|
||||
<x-ui.table.row>
|
||||
<td class="text-sm px-4">{{$deal->title}}</td>
|
||||
<x-slot:actions>
|
||||
<div class="flex items-center justify-center space-x-1 md:space-x-4 py-1 px-2">
|
||||
<x-ui.button-sm link="{{route('explore', ['show' => $deal->id])}}" variant="ghost">
|
||||
<x-heroicon-o-eye class="w-4"/>
|
||||
</x-ui.button-sm>
|
||||
<form action="{{route('favorite', $deal->id)}}"
|
||||
onsubmit="return confirm('Are you sure to delete this ?')" method="post"
|
||||
class=" h-full items-center flex justify-center">
|
||||
@csrf
|
||||
<x-ui.button-sm variant="red">
|
||||
<x-heroicon-o-trash class="w-4"/>
|
||||
</x-ui.button-sm>
|
||||
</form>
|
||||
</div>
|
||||
</x-slot:actions>
|
||||
</x-ui.table.row>
|
||||
@empty
|
||||
<x-ui.table.row>
|
||||
<td colspan="2" class="text-center text-sm text-accent-600 py-2">No Deals found</td>
|
||||
</x-ui.table.row>
|
||||
@endforelse
|
||||
</x-ui.table>
|
||||
</x-dashboard.card>
|
||||
</x-ui.tab.content>
|
||||
<x-ui.tab.content data-tab="reports">
|
||||
<x-dashboard.card class="bg-white mt-8">
|
||||
<p class="font-bold mb-6">Your reported deals</p>
|
||||
<x-ui.table>
|
||||
<x-ui.table.head>
|
||||
<th colspan="2" class="pb-2">Deals</th>
|
||||
</x-ui.table.head>
|
||||
@forelse($reported as $report)
|
||||
<x-ui.table.row>
|
||||
<td class="text-sm px-4">{{$report->deals->first()->title}}</td>
|
||||
<x-slot:actions>
|
||||
<div class="flex items-center justify-center py-1 px-2">
|
||||
<x-ui.button-sm link="{{route('explore', ['show' => $deal->id])}}" variant="ghost">
|
||||
<x-heroicon-o-eye class="w-4"/>
|
||||
</x-ui.button-sm>
|
||||
</div>
|
||||
</x-slot:actions>
|
||||
</x-ui.table.row>
|
||||
@empty
|
||||
<x-ui.table.row>
|
||||
<td colspan="2" class="text-center text-sm text-accent-600 py-2">No Deals found</td>
|
||||
</x-ui.table.row>
|
||||
@endforelse
|
||||
</x-ui.table>
|
||||
</x-dashboard.card>
|
||||
</x-ui.tab.content>
|
||||
</x-ui.tab>
|
||||
</div>
|
||||
</x-layout>
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
use App\Queries\ExplorePageDealsQuery;
|
||||
|
||||
Route::get('/deals/{deal}', function (Deal $deal) {
|
||||
sleep(2);
|
||||
return new DealResource(
|
||||
(new ExplorePageDealsQuery)
|
||||
->builder()
|
||||
|
||||
@ -17,9 +17,9 @@
|
||||
->middleware('throttle:30,1')
|
||||
->name('favorite');
|
||||
|
||||
Route::post('/report/{deal}', [ReportController::class, 'store'])
|
||||
Route::resource('report', ReportController::class)
|
||||
->middleware('throttle:5,1')
|
||||
->name('report.store');
|
||||
->only(['store', 'destroy']);
|
||||
|
||||
Route::get('/redirect/{deal}', [InteractionController::class, 'redirect'])
|
||||
->middleware(['throttle:10,1', 'signed'])
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user