File manager - Edit - /var/www/ratemypay/resources/views/components/network/post-card.blade.php
Back
@props(['post']) <div x-data="{ likesCount: {{ $post->likes_count }}, isLiked: {{ $post->is_liked_by_user ? 'true' : 'false' }}, avgRating: {{ $post->average_rating ?? 0 }}, ratingsCount: {{ $post->ratings_count ?? 0 }}, showComments: false, commentText: '', commentsCount: {{ $post->comments_count }}, isSubmitting: false, replyToId: null, newComments: [], newReplies: {}, async toggleLike() { this.isLiked = !this.isLiked; this.likesCount += this.isLiked ? 1 : -1; try { await fetch('{{ route('rate-my-pay.like', $post->id) }}', { method: 'POST', headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}', 'Accept': 'application/json' } }); } catch (e) { this.isLiked = !this.isLiked; this.likesCount += this.isLiked ? 1 : -1; } }, async submitComment(parentId = null) { let content = ''; if (parentId) { const el = document.getElementById('replyInput_' + parentId); content = el ? el.value : ''; } else { content = this.commentText; } if (!content.trim()) return; this.isSubmitting = true; try { const response = await fetch('{{ route('rate-my-pay.comments.store', $post->id) }}', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': '{{ csrf_token() }}', 'Accept': 'application/json' }, body: JSON.stringify({ content: content, parent_id: parentId }) }); const data = await response.json(); if (response.ok && data.status) { this.commentsCount = data.comments_count; const newComment = data.comment; if (parentId) { if (!this.newReplies[parentId]) this.newReplies[parentId] = []; this.newReplies[parentId].push(newComment); const el = document.getElementById('replyInput_' + parentId); if(el) el.value = ''; this.replyToId = null; } else { this.newComments.unshift(newComment); this.commentText = ''; } } } catch (e) { console.error(e); } finally { this.isSubmitting = false; } }, // FIXED: Removed '&background=random'. // Now it generates the same color hash as the server. avatarUrl(name) { return `https://ui-avatars.com/api/?name=${encodeURIComponent(name)}`; } }" class="w-full md:w-[100%] bg-white rounded-xl border border-gray-200 shadow-sm hover:shadow-md transition-shadow mb-6 overflow-hidden" > <a href="{{ route('rate-my-pay.show', $post->id) }}" class="block p-6"> {{-- Header --}} <div class="flex justify-between items-start mb-4"> <div class="flex gap-3 flex-1"> <div class="w-12 h-12 rounded-full bg-gradient-to-br from-blue-100 to-blue-50 border border-blue-100 flex items-center justify-center shrink-0"> <div class="bg-[#2F3D7E] rounded-full p-1.5"> <svg class="w-4 h-4 text-white" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10"/></svg> </div> </div> <div class="min-w-0 flex-1"> <div class="md:flex block items-center gap-2 flex-wrap"> <h3 class="font-bold text-gray-900 text-lg line-clamp-2 min-w-0 flex-1 hover:text-[#2F3D7E] transition-colors"> {{ $post->jobExperience->job_title ?? 'Role Unavailable' }} </h3> @if($post->communities->isNotEmpty()) <span class="inline-flex items-center rounded-full border border-blue-100 bg-blue-50 px-2 py-0.5 text-[10px] font-semibold text-[#2F3D7E] hover:bg-blue-100 transition-colors"> From {{ $post->communities->first()->name }} </span> @endif </div> <div class="flex items-center gap-3 text-sm text-gray-500 mt-1 flex-wrap"> @if(!$post->is_anonymous && $post->jobExperience && $post->jobExperience->company_name) <span class="flex items-center gap-1"> <svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="16" height="20" x="4" y="2" rx="2" ry="2"/><path d="M9 22v-4h6v4"/><path d="M8 6h.01"/><path d="M16 6h.01"/><path d="M12 6h.01"/><path d="M12 10h.01"/><path d="M12 14h.01"/><path d="M16 10h.01"/><path d="M16 14h.01"/><path d="M8 10h.01"/><path d="M8 14h.01"/></svg> {{ $post->jobExperience->company_name }} </span> @endif <span class="flex items-center gap-1"> <svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z"/><circle cx="12" cy="10" r="3"/></svg> {{ $post->jobExperience->location ?? 'Remote' }} </span> <span class="flex items-center gap-1"> <svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg> {{ $post->created_at->diffForHumans() }} </span> </div> </div> </div> </div> {{-- Content --}} @if($post->content) <p class="text-gray-600 text-sm mb-4 leading-relaxed">{{ $post->content }}</p> @endif {{-- Payslip --}} @if($post->payslip_url) <div class="mb-4 space-y-3"> <div class="bg-slate-100 rounded-lg overflow-hidden border border-slate-200 relative group cursor-pointer"> <div class="aspect-[4/3] bg-white relative"> <img src="{{ $post->payslip_url }}" alt="Verified Payslip" class="w-full h-full object-cover opacity-95 group-hover:opacity-100 transition-opacity"> <div class="absolute inset-0 bg-gradient-to-t from-black/40 to-transparent opacity-60"></div> <div class="absolute top-3 right-3"> <div class="inline-flex items-center rounded-full border border-transparent bg-green-500/90 px-2.5 py-0.5 text-xs font-semibold text-white shadow-sm backdrop-blur-sm gap-1.5"> <svg class="w-3 h-3 fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10"/></svg> Verified Pay </div> </div> </div> </div> </div> @endif {{-- Tags --}} <div class=" mb-4 p-4" style=" background: linear-gradient(90deg, rgba(45, 62, 110, 0.05) 0%, rgba(255, 87, 51, 0.05) 100%); "> {{-- <span class="px-2 py-1 bg-green-50 text-green-700 border border-green-100 text-xs rounded-md font-medium">{{ $post->formatted_salary }}</span> @if($post->jobExperience) <span class="px-2 py-1 bg-gray-100 text-gray-600 text-xs rounded-md font-medium">{{ $post->jobExperience->years_of_experience }} Years Exp</span> @endif --}} <div class="flex items-center"> <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M9 1.5V16.5" stroke="#2D3E6E" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> <path d="M12.75 3.75H7.125C6.42881 3.75 5.76113 4.02656 5.26884 4.51884C4.77656 5.01113 4.5 5.67881 4.5 6.375C4.5 7.07119 4.77656 7.73887 5.26884 8.23116C5.76113 8.72344 6.42881 9 7.125 9H10.875C11.5712 9 12.2389 9.27656 12.7312 9.76884C13.2234 10.2611 13.5 10.9288 13.5 11.625C13.5 12.3212 13.2234 12.9889 12.7312 13.4812C12.2389 13.9734 11.5712 14.25 10.875 14.25H4.5" stroke="#2D3E6E" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </svg> <span>Salary Details</span> </div> <div class="flex flex-wrap gap-6 mt-6"> <div class="flex-1 min-w-[120px]"> <div class="text-sm text-gray-500">Annual Base Salary</div> <div class="font-semibold">{{ $post->jobExperience->currency }} {{number_format($post->jobExperience->annual_base_salary, 0)}} </div> </div> <div class="flex-1 min-w-[120px]"> <div class="text-sm text-gray-500">Bonus</div> <div class="font-semibold">{{ $post->jobExperience->currency }} {{number_format($post->jobExperience->bonus_commission, 0)}} </div> </div> <div class="flex-1 min-w-[120px]"> <div class="text-sm text-gray-500">Total Comp</div> <div class="font-semibold">{{ $post->jobExperience->currency }} {{number_format($post->jobExperience->annual_base_salary + $post->jobExperience->bonus_commission, 0)}}</div> </div> <div class="flex-1 min-w-[120px]"> <div class="text-sm text-gray-500">Experience</div> <div class="font-semibold">{{$post->jobExperience->years_of_experience}} years</div> </div> </div> <div class="mt-6 md:flex w-full gap-4"> <div>Community Rating: <b x-text="avgRating.toFixed(1)"></b></div> <div class="text-gray-500 flex items-center gap-1"> <template x-for="star in 5" :key="star"> <i class="fa-star" :class="star <= Math.round(avgRating) ? 'fa-solid color-yellow' : 'fa-regular'"></i> </template> <span class="ml-1"> (<span x-text="ratingsCount"></span> ratings) </span> </div> </div> </div> </a> {{-- Actions --}} <div class="flex items-center gap-6 pt-4 px-6 pb-6 border-t border-gray-100"> <button @click="toggleLike()" class="flex items-center gap-2 text-sm transition-colors" :class="isLiked ? 'text-[#2F3D7E] font-medium' : 'text-gray-500 hover:text-[#2F3D7E]'"> <svg class="w-4 h-4" width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> <g clip-path="url(#clip0_41_28052)"> <path d="M5.25 7.5V16.5" stroke="#4A5565" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> <path d="M11.25 4.41L10.5 7.5H14.8725C15.1054 7.5 15.335 7.55422 15.5433 7.65836C15.7516 7.7625 15.9328 7.91371 16.0725 8.1C16.2122 8.28629 16.3066 8.50256 16.3483 8.73167C16.39 8.96078 16.3777 9.19645 16.3125 9.42L14.565 15.42C14.4741 15.7316 14.2846 16.0053 14.025 16.2C13.7654 16.3947 13.4496 16.5 13.125 16.5H3C2.60218 16.5 2.22064 16.342 1.93934 16.0607C1.65804 15.7794 1.5 15.3978 1.5 15V9C1.5 8.60218 1.65804 8.22064 1.93934 7.93934C2.22064 7.65804 2.60218 7.5 3 7.5H5.07C5.34906 7.49985 5.62255 7.42186 5.85972 7.27479C6.09688 7.12772 6.28832 6.91741 6.4125 6.6675L9 1.5C9.35368 1.50438 9.7018 1.58863 10.0184 1.74645C10.3349 1.90427 10.6117 2.13158 10.8281 2.4114C11.0444 2.69122 11.1947 3.01632 11.2678 3.3624C11.3409 3.70848 11.3348 4.0666 11.25 4.41Z" stroke="#4A5565" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </g> <defs> <clipPath id="clip0_41_28052"> <rect width="18" height="18" fill="white" /> </clipPath> </defs> </svg> <span x-text="likesCount"></span> </button> <!-- <button @click="showComments = !showComments" class="flex items-center gap-2 text-sm text-gray-500 hover:text-[#2F3D7E] transition-colors"> <svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg> <span x-text="commentsCount"></span> </button> --> <!-- <button class="flex items-center gap-2 text-sm text-gray-500 hover:text-[#2F3D7E] transition-colors ml-auto"> <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> <g clip-path="url(#clip0_41_28058)"> <path d="M5.925 15C7.35643 15.7343 9.00306 15.9332 10.5682 15.5609C12.1333 15.1885 13.5139 14.2694 14.4613 12.9692C15.4087 11.6689 15.8606 10.0731 15.7354 8.46916C15.6103 6.86524 14.9164 5.35876 13.7789 4.22118C12.6413 3.0836 11.1348 2.38972 9.53088 2.2646C7.92697 2.13947 6.3311 2.59132 5.03086 3.53872C3.73063 4.48612 2.81152 5.86677 2.43917 7.43187C2.06682 8.99697 2.26571 10.6436 3 12.075L1.5 16.5L5.925 15Z" stroke="#4A5565" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </g> <defs> <clipPath id="clip0_41_28058"> <rect width="18" height="18" fill="white" /> </clipPath> </defs> </svg> <span>Share</span> </button> --> </div> {{-- Comments Section --}} <div x-show="showComments" class="mt-4 pt-4 border-t border-gray-100 bg-gray-50 -mx-6 -mb-6 px-6 pb-6 rounded-b-xl" style="display: none;"> {{-- Main Comment Input --}} <div class="flex gap-3 mb-6"> <div class="w-8 h-8 rounded-full bg-gray-200 flex-shrink-0 overflow-hidden"> <img src="https://ui-avatars.com/api/?name={{ urlencode(auth()->user()->name) }}" class="w-full h-full"> </div> <div class="flex-1"> <textarea x-model="commentText" placeholder="Write a comment..." class="w-full border border-gray-300 rounded-lg p-2 text-sm focus:ring-1 focus:ring-[#2F3D7E] focus:border-[#2F3D7E] min-h-[40px] resize-none" rows="2"></textarea> <div class="flex justify-end mt-2"> <button @click="submitComment()" :disabled="isSubmitting || !commentText.trim()" class="px-3 py-1.5 bg-[#2F3D7E] text-white text-xs font-semibold rounded-md disabled:opacity-50 hover:bg-[#232d5e] transition-colors"> <span x-show="!isSubmitting">Post Comment</span> <span x-show="isSubmitting">Posting...</span> </button> </div> </div> </div> {{-- COMMENTS LIST --}} <div class="space-y-4"> {{-- NEW Comments (Alpine) --}} <template x-for="comment in newComments" :key="comment.id"> <div x-data="{ likes: 0, isLiked: false, toggleLike() { this.isLiked = !this.isLiked; this.likes += this.isLiked ? 1 : -1; fetch('/rate-my-pay/comments/' + comment.id + '/like', { method: 'POST', headers: {'X-CSRF-TOKEN': '{{ csrf_token() }}'} }); } }"> <div class="flex gap-3"> <img :src="avatarUrl(comment.author_name)" class="w-8 h-8 rounded-full bg-gray-200 flex-shrink-0"> <div class="flex-1"> <div class="bg-white p-3 rounded-lg border border-gray-200 shadow-sm"> <div class="flex justify-between items-start"> <span class="font-bold text-xs text-gray-900" x-text="comment.author_name"></span> <span class="text-[10px] text-gray-400">Just now</span> </div> <p class="text-sm text-gray-700 mt-1" x-text="comment.content"></p> </div> <div class="flex items-center gap-4 mt-1 pl-1"> <button @click="toggleLike()" class="text-xs font-medium text-gray-500 hover:text-gray-800 flex items-center gap-1"> <span x-text="isLiked ? 'Unlike' : 'Like'"></span> <span x-show="likes > 0" x-text="'(' + likes + ')'"></span> </button> <button @click="replyToId = (replyToId === comment.id ? null : comment.id)" class="text-xs font-medium text-gray-500 hover:text-gray-800">Reply</button> </div> {{-- Reply Input for NEW Comments --}} <div x-show="replyToId === comment.id" class="mt-3 flex gap-2"> <input :id="'replyInput_' + comment.id" type="text" placeholder="Write a reply..." class="flex-1 border border-gray-300 rounded-md px-2 py-1 text-sm focus:ring-[#2F3D7E] focus:border-[#2F3D7E]"> <button @click="submitComment(comment.id)" class="px-3 py-1 bg-[#2F3D7E] text-white text-xs rounded-md">Reply</button> </div> <div class="ml-11 mt-3 space-y-3" x-show="newReplies[comment.id] && newReplies[comment.id].length > 0"> <template x-for="reply in newReplies[comment.id]" :key="reply.id"> <div class="flex gap-3"> <img :src="avatarUrl(reply.author_name)" class="w-6 h-6 rounded-full bg-gray-200 flex-shrink-0"> <div class="flex-1"> <div class="bg-gray-100 p-2.5 rounded-lg border border-gray-200"> <div class="flex justify-between items-start"> <span class="font-bold text-xs text-gray-900" x-text="reply.author_name"></span> <span class="text-[10px] text-gray-400">Just now</span> </div> <p class="text-xs text-gray-700 mt-1" x-text="reply.content"></p> </div> </div> </div> </template> </div> </div> </div> </div> </template> {{-- EXISTING Comments (Server side) --}} @foreach($post->comments->sortByDesc('created_at') as $comment) <div> <x-network.comment-item :comment="$comment" /> <div class="ml-11 mt-3 space-y-3" x-show="newReplies[{{ $comment->id }}] && newReplies[{{ $comment->id }}].length > 0"> <template x-for="reply in newReplies[{{ $comment->id }}]" :key="reply.id"> <div class="flex gap-3"> <img :src="avatarUrl(reply.author_name)" class="w-6 h-6 rounded-full bg-gray-200 flex-shrink-0"> <div class="flex-1"> <div class="bg-gray-100 p-2.5 rounded-lg border border-gray-200"> <div class="flex justify-between items-start"> <span class="font-bold text-xs text-gray-900" x-text="reply.author_name"></span> <span class="text-[10px] text-gray-400">Just now</span> </div> <p class="text-xs text-gray-700 mt-1" x-text="reply.content"></p> </div> </div> </div> </template> </div> @if($comment->replies->count() > 0) <div class="ml-11 mt-3 space-y-3"> @foreach($comment->replies as $reply) <x-network.comment-item :comment="$reply" is-reply="true" /> @endforeach </div> @endif </div> @endforeach </div> </div> </div>
| ver. 1.4 |
Github
|
.
| PHP 8.3.30 | Generation time: 0 |
proxy
|
phpinfo
|
Settings