65 lines
2.2 KiB
PHP
65 lines
2.2 KiB
PHP
@props(['product', 'size' => 'sm'])
|
|
|
|
@php
|
|
$isUpvoted = auth()->check() && $product->isUpvotedBy(auth()->user());
|
|
$upvotesCount = isset($product->upvotes_count) ? $product->upvotes_count : $product->upvotes()->count();
|
|
|
|
$sizeClasses = match($size) {
|
|
'lg' => 'h-12 w-12 text-base',
|
|
'md' => 'h-10 w-10 text-sm',
|
|
default => 'h-8 w-8 text-xs',
|
|
};
|
|
@endphp
|
|
|
|
<div x-data="{
|
|
upvoted: {{ $isUpvoted ? 'true' : 'false' }},
|
|
count: {{ $upvotesCount }},
|
|
loading: false,
|
|
toggleUpvote() {
|
|
@guest
|
|
window.location.href = '{{ route('login') }}';
|
|
return;
|
|
@endguest
|
|
|
|
if (this.loading) return;
|
|
this.loading = true;
|
|
|
|
fetch('{{ route('products.upvote', $product) }}', {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json',
|
|
},
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
this.upvoted = data.upvoted;
|
|
this.count = data.upvotes_count;
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
})
|
|
.finally(() => {
|
|
this.loading = false;
|
|
});
|
|
}
|
|
}" class="flex-shrink-0">
|
|
<button @click="toggleUpvote()"
|
|
:disabled="loading"
|
|
:class="{
|
|
'bg-primary-100 border-primary-500 text-primary-700': upvoted,
|
|
'bg-white border-gray-300 text-gray-700 hover:border-gray-400': !upvoted
|
|
}"
|
|
class="{{ $sizeClasses }} flex flex-col items-center justify-center border-2 rounded-lg transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed">
|
|
<svg :class="{ 'animate-bounce': loading }"
|
|
class="w-4 h-4"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7"></path>
|
|
</svg>
|
|
<span class="font-semibold" x-text="count"></span>
|
|
</button>
|
|
</div>
|