feature(users can comment on deals)
This commit is contained in:
parent
aa7e2f245f
commit
a06fac4fef
@ -5,8 +5,8 @@
|
|||||||
use App\Enums\ReportStatus;
|
use App\Enums\ReportStatus;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Report;
|
use App\Models\Report;
|
||||||
use App\Notifications\ReportResolvedNotificationToBroker;
|
|
||||||
use App\Notifications\ReportRejectedNotificationToUser;
|
use App\Notifications\ReportRejectedNotificationToUser;
|
||||||
|
use App\Notifications\ReportResolvedNotificationToBroker;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class ReportController extends Controller
|
class ReportController extends Controller
|
||||||
|
|||||||
@ -46,7 +46,7 @@ public function verify(Request $request, VerifyOTPAction $otpAction)
|
|||||||
$data = $request->validate(['otp' => 'required|string:min:5:max:6']);
|
$data = $request->validate(['otp' => 'required|string:min:5:max:6']);
|
||||||
try {
|
try {
|
||||||
$isVerified = $otpAction->execute($data);
|
$isVerified = $otpAction->execute($data);
|
||||||
if (!$isVerified) {
|
if (! $isVerified) {
|
||||||
return back()->with('error', 'Invalid OTP');
|
return back()->with('error', 'Invalid OTP');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ public function update(Request $request)
|
|||||||
'password' => 'required', 'confirmed', Password::min(8)->letters()->mixedCase()->numbers()->symbols(),
|
'password' => 'required', 'confirmed', Password::min(8)->letters()->mixedCase()->numbers()->symbols(),
|
||||||
]);
|
]);
|
||||||
$user = User::find(Session::get('otp_user_id'));
|
$user = User::find(Session::get('otp_user_id'));
|
||||||
if (!$user) {
|
if (! $user) {
|
||||||
return back()->with('error', 'Session Expired');
|
return back()->with('error', 'Session Expired');
|
||||||
}
|
}
|
||||||
$user->update(['password' => $data['password']]);
|
$user->update(['password' => $data['password']]);
|
||||||
|
|||||||
44
app/Http/Controllers/CommentController.php
Normal file
44
app/Http/Controllers/CommentController.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Requests\CommentRequest;
|
||||||
|
use App\Models\Comment;
|
||||||
|
use App\Models\Deal;
|
||||||
|
|
||||||
|
class CommentController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Deal $deal)
|
||||||
|
{
|
||||||
|
$comments = $deal->comments()->with('user')->latest()->get();
|
||||||
|
$html = view('components.dashboard.user.deal-comment.index', compact('comments'))->render();
|
||||||
|
|
||||||
|
return response()->json(['html' => $html]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Deal $deal, CommentRequest $request)
|
||||||
|
{
|
||||||
|
$data = $request->validated();
|
||||||
|
$data['user_id'] = $request->user()->id;
|
||||||
|
$data['deal_id'] = $deal->id;
|
||||||
|
|
||||||
|
Comment::create($data);
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Comment created successfully.'], 201);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(Comment $comment) {}
|
||||||
|
|
||||||
|
public function update(CommentRequest $request, Comment $comment)
|
||||||
|
{
|
||||||
|
$comment->update($request->validated());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(Comment $comment)
|
||||||
|
{
|
||||||
|
$comment->delete();
|
||||||
|
|
||||||
|
return response()->json();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,9 +15,11 @@ public function __invoke(ContactRequest $request)
|
|||||||
$data = $request->validated();
|
$data = $request->validated();
|
||||||
$admin = Admin::first();
|
$admin = Admin::first();
|
||||||
$admin->user->notify(new NewContactNotification($data['name'], $data['email'], $data['message']));
|
$admin->user->notify(new NewContactNotification($data['name'], $data['email'], $data['message']));
|
||||||
|
|
||||||
return back()->with('success', 'Your message has been sent successfully.');
|
return back()->with('success', 'Your message has been sent successfully.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
\Log::error('Error sending contact message', [$e->getMessage()]);
|
\Log::error('Error sending contact message', [$e->getMessage()]);
|
||||||
|
|
||||||
return back()->with('error', 'Something went wrong.');
|
return back()->with('error', 'Something went wrong.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
20
app/Http/Requests/CommentRequest.php
Normal file
20
app/Http/Requests/CommentRequest.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class CommentRequest extends FormRequest
|
||||||
|
{
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'text' => ['required', 'string', 'max:255'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -27,8 +27,9 @@ public function rules(): array
|
|||||||
'message' => 'required|string|min:10|max:255',
|
'message' => 'required|string|min:10|max:255',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getRedirectUrl(): string
|
protected function getRedirectUrl(): string
|
||||||
{
|
{
|
||||||
return parent::getRedirectUrl() . '#contact';
|
return parent::getRedirectUrl().'#contact';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
25
app/Models/Comment.php
Normal file
25
app/Models/Comment.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
|
class Comment extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'text',
|
||||||
|
'deal_id',
|
||||||
|
'user_id',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function deal(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Deal::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -76,6 +76,11 @@ public function reports(): BelongsToMany
|
|||||||
return $this->belongsToMany(Report::class);
|
return $this->belongsToMany(Report::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function comments(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Comment::class);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scope a query to only include active deals
|
* Scope a query to only include active deals
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -152,4 +152,9 @@ public function reports(): HasMany
|
|||||||
{
|
{
|
||||||
return $this->hasMany(Report::class);
|
return $this->hasMany(Report::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function comments(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Comment::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,8 +15,7 @@ public function __construct(
|
|||||||
private readonly string $customerName,
|
private readonly string $customerName,
|
||||||
private readonly string $customerEmail,
|
private readonly string $customerEmail,
|
||||||
private readonly string $customerMessage
|
private readonly string $customerMessage
|
||||||
) {
|
) {}
|
||||||
}
|
|
||||||
|
|
||||||
public function via($notifiable): array
|
public function via($notifiable): array
|
||||||
{
|
{
|
||||||
@ -31,9 +30,8 @@ public function toMail($notifiable): MailMessage
|
|||||||
->line('You have received a new message from your contact form:')
|
->line('You have received a new message from your contact form:')
|
||||||
->line("**Name:** {$this->customerName}")
|
->line("**Name:** {$this->customerName}")
|
||||||
->line("**Email:** {$this->customerEmail}")
|
->line("**Email:** {$this->customerEmail}")
|
||||||
->line("**Message:**")
|
->line('**Message:**')
|
||||||
->line($this->customerMessage)
|
->line($this->customerMessage)
|
||||||
->action('Reply via Email', 'mailto:'.$this->customerEmail);;
|
->action('Reply via Email', 'mailto:'.$this->customerEmail);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,8 +13,7 @@ class ReportRejectedNotificationToUser extends Notification implements ShouldQue
|
|||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly string $dealTitle,
|
private readonly string $dealTitle,
|
||||||
) {
|
) {}
|
||||||
}
|
|
||||||
|
|
||||||
public function via($notifiable): array
|
public function via($notifiable): array
|
||||||
{
|
{
|
||||||
@ -27,9 +26,9 @@ public function toMail($notifiable): MailMessage
|
|||||||
return (new MailMessage)
|
return (new MailMessage)
|
||||||
->subject('Update on Your Recent Report: '.$this->dealTitle)
|
->subject('Update on Your Recent Report: '.$this->dealTitle)
|
||||||
->greeting('Hello!')
|
->greeting('Hello!')
|
||||||
->line("Thank you for helping us maintain the integrity of our marketplace.")
|
->line('Thank you for helping us maintain the integrity of our marketplace.')
|
||||||
->line("We have completed our review of the deal you reported: **{$this->dealTitle}**.")
|
->line("We have completed our review of the deal you reported: **{$this->dealTitle}**.")
|
||||||
->line("Based on our moderation policy, we have rejected your report.")
|
->line('Based on our moderation policy, we have rejected your report.')
|
||||||
->action('View Marketplace', route('explore'))
|
->action('View Marketplace', route('explore'))
|
||||||
->line('Your feedback helps make our community a safer place for everyone.');
|
->line('Your feedback helps make our community a safer place for everyone.');
|
||||||
}
|
}
|
||||||
@ -38,7 +37,7 @@ public function toArray($notifiable): array
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'report_outcome' => $this->isContentRemoved ? 'violation_confirmed' : 'no_violation_found',
|
'report_outcome' => $this->isContentRemoved ? 'violation_confirmed' : 'no_violation_found',
|
||||||
'deal_title' => $this->dealTitle
|
'deal_title' => $this->dealTitle,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,8 +14,7 @@ class ReportResolvedNotificationToBroker extends Notification implements ShouldQ
|
|||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly string $dealTitle,
|
private readonly string $dealTitle,
|
||||||
private readonly bool $isContentRemoved
|
private readonly bool $isContentRemoved
|
||||||
) {
|
) {}
|
||||||
}
|
|
||||||
|
|
||||||
public function via($notifiable): array
|
public function via($notifiable): array
|
||||||
{
|
{
|
||||||
|
|||||||
@ -14,8 +14,7 @@ class ReportResolvedNotificationToUser extends Notification implements ShouldQue
|
|||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly string $dealTitle,
|
private readonly string $dealTitle,
|
||||||
private readonly bool $isContentRemoved
|
private readonly bool $isContentRemoved
|
||||||
) {
|
) {}
|
||||||
}
|
|
||||||
|
|
||||||
public function via($notifiable): array
|
public function via($notifiable): array
|
||||||
{
|
{
|
||||||
@ -31,7 +30,7 @@ public function toMail($notifiable): MailMessage
|
|||||||
return (new MailMessage)
|
return (new MailMessage)
|
||||||
->subject('Update on Your Recent Report: '.$this->dealTitle)
|
->subject('Update on Your Recent Report: '.$this->dealTitle)
|
||||||
->greeting('Hello!')
|
->greeting('Hello!')
|
||||||
->line("Thank you for helping us maintain the integrity of our marketplace.")
|
->line('Thank you for helping us maintain the integrity of our marketplace.')
|
||||||
->line("We have completed our review of the deal you reported: **{$this->dealTitle}**.")
|
->line("We have completed our review of the deal you reported: **{$this->dealTitle}**.")
|
||||||
->line("Based on our moderation policy, the content {$outcome}")
|
->line("Based on our moderation policy, the content {$outcome}")
|
||||||
->action('View Marketplace', route('explore'))
|
->action('View Marketplace', route('explore'))
|
||||||
@ -42,7 +41,7 @@ public function toArray($notifiable): array
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'report_outcome' => $this->isContentRemoved ? 'violation_confirmed' : 'no_violation_found',
|
'report_outcome' => $this->isContentRemoved ? 'violation_confirmed' : 'no_violation_found',
|
||||||
'deal_title' => $this->dealTitle
|
'deal_title' => $this->dealTitle,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Deal;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('comments', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('text');
|
||||||
|
$table->foreignIdFor(Deal::class);
|
||||||
|
$table->foreignIdFor(User::class);
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('comments');
|
||||||
|
}
|
||||||
|
};
|
||||||
22
resources/js/comments.js
Normal file
22
resources/js/comments.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
export const postComment = async (dealId, text) => {
|
||||||
|
try {
|
||||||
|
let data = {
|
||||||
|
deal_id: dealId,
|
||||||
|
text: text
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await axios.post(`/api/deals/${dealId}/comments`, data)
|
||||||
|
console.log(response)
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getComments = async (dealId) => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`/api/deals/${dealId}/comments`)
|
||||||
|
return response.data.html
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@ import {showToast} from "@/toast.js";
|
|||||||
import {closeModal, showModal} from "@/modal.js";
|
import {closeModal, showModal} from "@/modal.js";
|
||||||
import {redirect} from "./interaction.js";
|
import {redirect} from "./interaction.js";
|
||||||
import {toggleShimmer} from "./shimmer.js";
|
import {toggleShimmer} from "./shimmer.js";
|
||||||
|
import {getComments, postComment} from "./comments.js";
|
||||||
|
|
||||||
export async function showDealModal(dealId) {
|
export async function showDealModal(dealId) {
|
||||||
if (!dealId) {
|
if (!dealId) {
|
||||||
@ -11,6 +12,7 @@ export async function showDealModal(dealId) {
|
|||||||
|
|
||||||
const dealModal = document.getElementById('deal-modal');
|
const dealModal = document.getElementById('deal-modal');
|
||||||
|
|
||||||
|
|
||||||
showModal('deal-modal');
|
showModal('deal-modal');
|
||||||
|
|
||||||
toggleShimmer(false, dealModal);
|
toggleShimmer(false, dealModal);
|
||||||
@ -19,6 +21,8 @@ export async function showDealModal(dealId) {
|
|||||||
const response = await axios.get('/api/deals/' + dealId);
|
const response = await axios.get('/api/deals/' + dealId);
|
||||||
setDealDetails(response.data);
|
setDealDetails(response.data);
|
||||||
|
|
||||||
|
await setComments(dealId, dealModal);
|
||||||
|
|
||||||
toggleShimmer(true, dealModal);
|
toggleShimmer(true, dealModal);
|
||||||
|
|
||||||
dealModal.dataset.dealId = dealId;
|
dealModal.dataset.dealId = dealId;
|
||||||
@ -37,10 +41,7 @@ function setDealDetails(dealDetails) {
|
|||||||
|
|
||||||
const deal = dealDetails.data
|
const deal = dealDetails.data
|
||||||
const {
|
const {
|
||||||
id, title, description, link,
|
id, title, description, link, image, category, broker, totalRedirection, totalLikes, isLiked, isFavorite
|
||||||
image, category, broker,
|
|
||||||
totalRedirection, totalLikes,
|
|
||||||
isLiked, isFavorite
|
|
||||||
} = deal;
|
} = deal;
|
||||||
const dealModal = document.getElementById('deal-modal');
|
const dealModal = document.getElementById('deal-modal');
|
||||||
|
|
||||||
@ -89,6 +90,13 @@ function setDealDetails(dealDetails) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function setComments(dealId, dealModal) {
|
||||||
|
const commentsContainer = dealModal.querySelector('.comments-container');
|
||||||
|
toggleShimmer(false, commentsContainer);
|
||||||
|
commentsContainer.innerHTML = await getComments(dealId);
|
||||||
|
toggleShimmer(true, commentsContainer);
|
||||||
|
}
|
||||||
|
|
||||||
window.addEventListener('DOMContentLoaded', () => {
|
window.addEventListener('DOMContentLoaded', () => {
|
||||||
const dealCards = document.querySelectorAll('.deal-card');
|
const dealCards = document.querySelectorAll('.deal-card');
|
||||||
if (dealCards) {
|
if (dealCards) {
|
||||||
@ -104,4 +112,18 @@ window.addEventListener('DOMContentLoaded', () => {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
const commentBtn = document.getElementById('commentSubmitBtn');
|
||||||
|
|
||||||
|
if (commentBtn) {
|
||||||
|
commentBtn.addEventListener('click', async () => {
|
||||||
|
const dealModal = document.getElementById('deal-modal');
|
||||||
|
const dealId = dealModal.dataset.dealId;
|
||||||
|
const textInput = dealModal.querySelector('input[name="comment"]');
|
||||||
|
let text = textInput.value;
|
||||||
|
textInput.value = '';
|
||||||
|
|
||||||
|
await postComment(dealId, text);
|
||||||
|
await setComments(dealId, dealModal);
|
||||||
|
})
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
@props(['broker' => ''])
|
@props(['broker' => ''])
|
||||||
<div class="p-4 text-sm bg-gray-100 border-gray-200 border rounded-xl">
|
<div {{$attributes->merge(['class' => "p-4 text-sm bg-gray-100 border-gray-200 border rounded-xl"])}}>
|
||||||
<p class="font-bold mb-2">Broker Contact</p>
|
<p class="font-bold mb-2">Broker Contact</p>
|
||||||
<div class="text-accent-600 space-y-1">
|
<div class="text-accent-600 space-y-1">
|
||||||
<p data-is-loading="false" class="broker-name">{{$broker->name ?? ''}}</p>
|
<p data-is-loading="false" class="broker-name">{{$broker->name ?? ''}}</p>
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
@props(['comments' => []])
|
||||||
|
<div data-is-loading="true" class="comments-container mt-2 space-y-2 max-h-40 overflow-y-scroll data-[is-loading=true]:h-10">
|
||||||
|
@forelse($comments as $comment)
|
||||||
|
<x-dashboard.user.deal-comment.item :comment="$comment"/>
|
||||||
|
@empty
|
||||||
|
<div class="rounded-lg bg-white border border-gray-200 py-2 px-3">
|
||||||
|
<p class="text-center text-accent-600">No comments posted !</p>
|
||||||
|
</div>
|
||||||
|
@endforelse
|
||||||
|
</div>
|
||||||
|
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
@props(['comment'])
|
||||||
|
<div class="rounded-lg bg-white border border-gray-200 py-2 px-3">
|
||||||
|
<p class="font-bold text-accent-600">{{$comment->user->name}}</p>
|
||||||
|
<p>{{$comment->text}}</p>
|
||||||
|
</div>
|
||||||
@ -1,19 +1,21 @@
|
|||||||
<x-ui.modal id="deal-modal" class="deal-identifier w-11/12 md:w-10/12">
|
<x-ui.modal id="deal-modal" class="deal-identifier w-11/12 md:w-10/12 overflow-scroll">
|
||||||
<form class="flex justify-between items-start mb-4" method="dialog">
|
<form class="flex justify-between items-start mb-4" method="dialog">
|
||||||
<p class="text-xl font-bold">Deal Details</p>
|
<p class="text-xl font-bold">Deal Details</p>
|
||||||
<button type="submit" class="">
|
<button type="submit" class="">
|
||||||
<x-heroicon-o-x-mark class="w-4"/>
|
<x-heroicon-o-x-mark class="w-4"/>
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<div class="grid md:grid-cols-12 gap-4 items-stretch">
|
<div class="grid md:grid-cols-12 gap-4 items-stretch mb-4">
|
||||||
<div data-is-loading="true" class="md:col-span-8 h-0 min-h-full data-[is-loading=true]:h-60">
|
<div data-is-loading="true" class="md:col-span-8 h-40 md:h-0 min-h-full data-[is-loading=true]:h-60">
|
||||||
<div class="rounded-lg bg-gray-200 h-full">
|
<div class="rounded-lg bg-gray-200 h-full">
|
||||||
<img src="" alt=" "
|
<img src="" alt=" "
|
||||||
class="deal-image h-full w-full object-cover rounded-lg border-none">
|
class="deal-image h-full w-full object-cover rounded-lg border-none">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="md:col-span-4 flex flex-col gap-y-4">
|
<div class="md:col-span-4 flex flex-col gap-y-4">
|
||||||
<x-ui.button-sm data-is-loading="true" class="w-fit deal-category data-[is-loading=true]:h-6 data-[is-loading=true]:w-15" variant="neutral"/>
|
<x-ui.button-sm data-is-loading="true"
|
||||||
|
class="w-fit deal-category data-[is-loading=true]:h-6 data-[is-loading=true]:w-15"
|
||||||
|
variant="neutral"/>
|
||||||
<p data-is-loading="true" class="deal-title font-bold text-lg data-[is-loading=true]:h-3 "></p>
|
<p data-is-loading="true" class="deal-title font-bold text-lg data-[is-loading=true]:h-3 "></p>
|
||||||
<p data-is-loading="true" class="deal-description text-sm text-accent-600 wrap-break-word"></p>
|
<p data-is-loading="true" class="deal-description text-sm text-accent-600 wrap-break-word"></p>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
@ -23,15 +25,26 @@ class="deal-image h-full w-full object-cover rounded-lg border-none">
|
|||||||
</div>
|
</div>
|
||||||
<x-dashboard.user.deal-stats/>
|
<x-dashboard.user.deal-stats/>
|
||||||
</div>
|
</div>
|
||||||
<x-ui.button variant="neutral" data-is-loading="false" class="hidden deal-link space-x-2 items-center justify-center">
|
<x-ui.button variant="neutral" data-is-loading="false"
|
||||||
|
class="hidden deal-link space-x-2 items-center justify-center">
|
||||||
<div class="flex space-x-2">
|
<div class="flex space-x-2">
|
||||||
<p>View Deal</p>
|
<p>View Deal</p>
|
||||||
<x-heroicon-o-arrow-top-right-on-square class="w-5 ml-1"/>
|
<x-heroicon-o-arrow-top-right-on-square class="w-5 ml-1"/>
|
||||||
</div>
|
</div>
|
||||||
</x-ui.button>
|
</x-ui.button>
|
||||||
<x-dashboard.user.broker-contact/>
|
<x-dashboard.user.broker-contact id="comments"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="p-2 text-sm bg-gray-50 border-gray-200 border rounded-xl">
|
||||||
|
<p class="font-bold mb-2">Comments</p>
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<x-ui.input class="flex-1" name="comment" placeholder="Add a comment..."/>
|
||||||
|
<x-ui.button id="commentSubmitBtn" variant="ghost" icon="paper-airplane">
|
||||||
|
<p class="hidden md:block">Comment</p>
|
||||||
|
</x-ui.button>
|
||||||
|
</div>
|
||||||
|
<x-dashboard.user.deal-comment/>
|
||||||
|
</div>
|
||||||
</x-ui.modal>
|
</x-ui.modal>
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
@props(['variant' => '', 'icon' => '', 'link' => '', 'external' => false, 'round' => false])
|
@props(['variant' => '', 'icon' => '', 'link' => '', 'external' => false, 'round' => false])
|
||||||
@php
|
@php
|
||||||
$variants = [
|
$variants = [
|
||||||
'neutral' => 'bg-primary-600 text-white',
|
'neutral' => 'bg-primary-600 text-white hover:bg-gray-200 hover:text-gray-900',
|
||||||
'red' => 'bg-red-500 text-white',
|
'red' => 'bg-red-500 text-white hover:bg-red-400 hover:text-red-800',
|
||||||
'ghost' => 'bg-gray-200 text-gray-900'
|
'ghost' => 'bg-gray-200 text-gray-900 hover:bg-primary-600 hover:text-white'
|
||||||
];
|
];
|
||||||
|
|
||||||
$variantClass = $variants[$variant] ?? '';
|
$variantClass = $variants[$variant] ?? '';
|
||||||
@ -29,13 +29,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
@else
|
@else
|
||||||
<button {{$attributes->merge(['class' => "font-medium hover:opacity-80 active:scale-80 transition-all ease-in-out duration-300 $variantClass", 'type'=>'submit'])}}>
|
<button {{$attributes->merge(['class' => "font-medium active:scale-80 transition-all ease-in-out duration-300 $variantClass", 'type'=>'submit'])}}>
|
||||||
<div class="flex justify-center items-center space-x-2">
|
<div class="flex justify-center items-center md:space-x-2">
|
||||||
@if($icon !=='')
|
@if($icon !=='')
|
||||||
@svg("heroicon-o-$icon", 'w-5 h-5')
|
@svg("heroicon-o-$icon", 'w-5 h-5')
|
||||||
@endif
|
@endif
|
||||||
@if(filled($slot))
|
@if(filled($slot))
|
||||||
<p>{{$slot}}</p>
|
{{$slot}}
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Http\Controllers\CommentController;
|
||||||
use App\Http\Controllers\Interaction\InteractionController;
|
use App\Http\Controllers\Interaction\InteractionController;
|
||||||
use App\Http\Controllers\Interaction\ReportController;
|
use App\Http\Controllers\Interaction\ReportController;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
@ -12,3 +13,5 @@
|
|||||||
Route::post('/report/{deal}', [ReportController::class, 'store'])->name('report-deal');
|
Route::post('/report/{deal}', [ReportController::class, 'store'])->name('report-deal');
|
||||||
Route::delete('/report/{deal}', [ReportController::class, 'destroy']);
|
Route::delete('/report/{deal}', [ReportController::class, 'destroy']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::apiResource('deals.comments', CommentController::class)->except(['update', 'edit', 'destroy']);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user