This commit is contained in:
Codex
2026-07-10 10:38:02 -05:00
parent 63820994f8
commit 42db078e47
51 changed files with 1173 additions and 26 deletions
+40
View File
@@ -0,0 +1,40 @@
<x-app-layout>
<x-slot name="header"><h2 class="text-xl font-semibold">Admin</h2></x-slot>
<div class="mx-auto max-w-7xl space-y-6 p-6">
<section class="grid gap-4 md:grid-cols-5">
@foreach ($counts as $label => $count)
<div class="rounded border bg-white p-4">
<p class="text-sm text-gray-500">{{ str_replace('_', ' ', $label) }}</p>
<p class="text-2xl font-semibold">{{ $count }}</p>
</div>
@endforeach
</section>
<section class="grid gap-6 lg:grid-cols-2">
<div class="rounded border bg-white p-6">
<h3 class="font-semibold">Recent users</h3>
@foreach ($users as $user)
<p class="mt-3 text-sm">{{ $user->name }} | {{ $user->email }} | {{ $user->roles->pluck('name')->join(', ') }}</p>
@endforeach
</div>
<div class="rounded border bg-white p-6">
<h3 class="font-semibold">Recent jobs</h3>
@foreach ($jobs as $job)
<p class="mt-3 text-sm"><a class="text-indigo-600" href="{{ route('jobs.show', $job) }}">{{ $job->title }}</a> | {{ $job->status }} | {{ $job->buyer->name }}</p>
@endforeach
</div>
<div class="rounded border bg-white p-6">
<h3 class="font-semibold">Recent work orders</h3>
@foreach ($workOrders as $order)
<p class="mt-3 text-sm"><a class="text-indigo-600" href="{{ route('work-orders.show', $order) }}">{{ $order->jobPost->title }}</a> | {{ $order->status }}</p>
@endforeach
</div>
<div class="rounded border bg-white p-6">
<h3 class="font-semibold">Recent disputes</h3>
@foreach ($disputes as $dispute)
<p class="mt-3 text-sm"><a class="text-indigo-600" href="{{ route('disputes.show', $dispute) }}">{{ $dispute->summary }}</a> | {{ $dispute->status }} | {{ $dispute->openedBy->name }}</p>
@endforeach
</div>
</section>
</div>
</x-app-layout>
+7
View File
@@ -15,5 +15,12 @@
<label class="flex gap-2 text-sm"><input type="checkbox" name="public_contact" value="1" @checked($profile?->public_contact)> Show contact details publicly</label>
<x-primary-button>Save buyer profile</x-primary-button>
</form>
@if ($profile)
<section class="mt-6 rounded border bg-white p-6">
<h3 class="font-semibold">Company photos and files</h3>
<x-attachments :attachments="$profile->attachments" />
<x-attachment-form type="buyer_profile" :id="$profile->id" kind="profile" />
</section>
@endif
</div>
</x-app-layout>
+1
View File
@@ -9,5 +9,6 @@
<div><dt class="text-sm text-gray-500">Vendor onboarding</dt><dd class="whitespace-pre-line">{{ $profile->vendor_onboarding }}</dd></div>
<div><dt class="text-sm text-gray-500">Payment terms</dt><dd class="whitespace-pre-line">{{ $profile->payment_terms }}</dd></div>
</dl>
<x-attachments :attachments="$profile->attachments" />
</div>
</x-app-layout>
@@ -0,0 +1,11 @@
@props(['type', 'id', 'kind' => 'general'])
<form method="POST" action="{{ route('attachments.store') }}" enctype="multipart/form-data" class="mt-4 space-y-3 rounded border p-4">
@csrf
<input type="hidden" name="attachable_type" value="{{ $type }}">
<input type="hidden" name="attachable_id" value="{{ $id }}">
<input type="hidden" name="kind" value="{{ $kind }}">
<x-field name="caption" label="Caption" />
<input type="file" name="file" required class="block w-full text-sm">
<x-primary-button>Upload file</x-primary-button>
</form>
@@ -0,0 +1,12 @@
@props(['attachments'])
@if ($attachments->count())
<div class="mt-4 grid gap-3 md:grid-cols-2">
@foreach ($attachments as $attachment)
<a href="{{ asset('storage/'.$attachment->path) }}" class="block rounded border p-3 text-sm" target="_blank">
<span class="font-semibold">{{ $attachment->original_name }}</span>
<span class="block text-gray-500">{{ $attachment->caption }}</span>
</a>
@endforeach
</div>
@endif
+39
View File
@@ -7,8 +7,47 @@
<p class="mt-2 whitespace-pre-line">{{ $dispute->claim }}</p>
<h3 class="mt-4 font-semibold">Evidence notes</h3>
<p class="mt-2 whitespace-pre-line">{{ $dispute->evidence_notes }}</p>
<x-attachments :attachments="$dispute->attachments" />
<x-attachment-form type="dispute" :id="$dispute->id" kind="evidence" />
<h3 class="mt-4 font-semibold">Recommended resolution</h3>
<p class="mt-2 whitespace-pre-line">{{ $dispute->recommended_resolution ?? 'Pending peer review.' }}</p>
</section>
<section class="rounded border bg-white p-6">
<h3 class="font-semibold">Peer votes</h3>
<form method="POST" action="{{ route('dispute-votes.store', $dispute) }}" class="mt-4 space-y-4">
@csrf
<label class="block text-sm font-medium">Recommendation</label>
<select name="recommendation" class="rounded-md border-gray-300">
<option value="provider">Provider position</option>
<option value="buyer">Buyer position</option>
<option value="split">Split resolution</option>
<option value="insufficient_evidence">Insufficient evidence</option>
</select>
<x-field name="reason" label="Reason" textarea />
<x-primary-button>Save vote</x-primary-button>
</form>
@foreach ($dispute->votes as $vote)
<div class="mt-3 rounded bg-gray-50 p-3 text-sm">
<p class="font-semibold">{{ $vote->user->name }} | {{ str_replace('_', ' ', $vote->recommendation) }}</p>
<p class="whitespace-pre-line">{{ $vote->reason }}</p>
</div>
@endforeach
</section>
<section class="rounded border bg-white p-6">
<h3 class="font-semibold">Comments</h3>
<form method="POST" action="{{ route('comments.store') }}" class="mt-4 space-y-4">
@csrf
<input type="hidden" name="commentable_type" value="dispute">
<input type="hidden" name="commentable_id" value="{{ $dispute->id }}">
<x-field name="body" label="Comment" textarea />
<x-primary-button>Comment</x-primary-button>
</form>
@foreach ($dispute->comments as $comment)
<div class="mt-3 rounded bg-gray-50 p-3 text-sm">
<p class="font-semibold">{{ $comment->user->name }}</p>
<p class="whitespace-pre-line">{{ $comment->body }}</p>
</div>
@endforeach
</section>
</div>
</x-app-layout>
+19
View File
@@ -15,6 +15,25 @@
<p class="text-sm text-gray-500">{{ $post->user->name }} | {{ $post->created_at->diffForHumans() }}</p>
@if ($post->title)<h3 class="mt-2 font-semibold">{{ $post->title }}</h3>@endif
<p class="mt-3 whitespace-pre-line">{{ $post->body }}</p>
<x-attachments :attachments="$post->attachments" />
@auth
@if ($post->user_id === auth()->id())
<x-attachment-form type="social_post" :id="$post->id" kind="post" />
@endif
<form method="POST" action="{{ route('comments.store') }}" class="mt-4 space-y-3">
@csrf
<input type="hidden" name="commentable_type" value="social_post">
<input type="hidden" name="commentable_id" value="{{ $post->id }}">
<x-field name="body" label="Comment" textarea />
<x-primary-button>Comment</x-primary-button>
</form>
@endauth
@foreach ($post->comments as $comment)
<div class="mt-3 rounded bg-gray-50 p-3 text-sm">
<p class="font-semibold">{{ $comment->user->name }}</p>
<p class="whitespace-pre-line">{{ $comment->body }}</p>
</div>
@endforeach
</article>
@endforeach
{{ $posts->links() }}
+47 -1
View File
@@ -10,6 +10,12 @@
<div><dt class="text-sm text-gray-500">Deliverables</dt><dd class="whitespace-pre-line">{{ $job->deliverables }}</dd></div>
<div><dt class="text-sm text-gray-500">Payment terms</dt><dd class="whitespace-pre-line">{{ $job->payment_terms }}</dd></div>
</dl>
<x-attachments :attachments="$job->attachments" />
@auth
@if (auth()->id() === $job->buyer_id)
<x-attachment-form type="job_post" :id="$job->id" kind="job" />
@endif
@endauth
</section>
@auth
@role('provider')
@@ -33,12 +39,34 @@
<p class="font-semibold">{{ $quote->provider->providerProfile?->business_name ?? $quote->provider->name }}</p>
<p class="text-sm text-gray-600">{{ $quote->status }} | {{ $quote->rate_summary }} | {{ $quote->requested_amount }}</p>
<p class="mt-2 whitespace-pre-line text-sm">{{ $quote->message }}</p>
@if ($quote->revisions->count())
<details class="mt-3 text-sm">
<summary class="cursor-pointer font-semibold">Revision history</summary>
@foreach ($quote->revisions as $revision)
<p class="mt-2 text-gray-600">{{ $revision->created_at->diffForHumans() }} | {{ $revision->action }} | {{ $revision->rate_summary }} | {{ $revision->requested_amount }}</p>
@endforeach
</details>
@endif
@auth
@if (auth()->id() === $quote->provider_id && in_array($quote->status, ['submitted', 'countered', 'revised'], true) && $job->status === 'open')
<form method="POST" action="{{ route('quotes.update', $quote) }}" class="mt-4 space-y-3 rounded bg-gray-50 p-3">
@csrf @method('PATCH')
<x-field name="requested_amount" label="Revised amount" type="number" :value="$quote->requested_amount" />
<x-field name="rate_summary" label="Rate summary" :value="$quote->rate_summary" />
<x-field name="message" label="Message" :value="$quote->message" textarea />
<x-field name="terms" label="Terms" :value="$quote->terms" textarea />
<x-primary-button>Revise quote</x-primary-button>
</form>
@endif
@if (auth()->id() === $job->buyer_id && $job->status === 'open')
<form method="POST" action="{{ route('quotes.accept', $quote) }}" class="mt-3">
<form method="POST" action="{{ route('quotes.accept', $quote) }}" class="mt-3 inline-block">
@csrf
<x-primary-button>Accept quote</x-primary-button>
</form>
<form method="POST" action="{{ route('quotes.decline', $quote) }}" class="mt-3 inline-block">
@csrf
<x-secondary-button>Decline</x-secondary-button>
</form>
@endif
@endauth
</div>
@@ -49,5 +77,23 @@
@if ($job->workOrder)
<a class="rounded bg-gray-900 px-4 py-2 text-white" href="{{ route('work-orders.show', $job->workOrder) }}">View work order</a>
@endif
<section class="rounded border bg-white p-6">
<h3 class="font-semibold">Discussion</h3>
@auth
<form method="POST" action="{{ route('comments.store') }}" class="mt-4 space-y-3">
@csrf
<input type="hidden" name="commentable_type" value="job_post">
<input type="hidden" name="commentable_id" value="{{ $job->id }}">
<x-field name="body" label="Comment" textarea />
<x-primary-button>Comment</x-primary-button>
</form>
@endauth
@foreach ($job->comments as $comment)
<div class="mt-3 rounded bg-gray-50 p-3 text-sm">
<p class="font-semibold">{{ $comment->user->name }}</p>
<p class="whitespace-pre-line">{{ $comment->body }}</p>
</div>
@endforeach
</section>
</div>
</x-app-layout>
@@ -30,6 +30,11 @@
<x-nav-link :href="route('work-orders.index')" :active="request()->routeIs('work-orders.*')">
{{ __('Work Orders') }}
</x-nav-link>
@role('admin')
<x-nav-link :href="route('admin.index')" :active="request()->routeIs('admin.*')">
{{ __('Admin') }}
</x-nav-link>
@endrole
</div>
</div>
@@ -117,6 +122,13 @@
<x-responsive-nav-link :href="route('work-orders.index')" :active="request()->routeIs('work-orders.*')">
{{ __('Work Orders') }}
</x-responsive-nav-link>
@auth
@role('admin')
<x-responsive-nav-link :href="route('admin.index')" :active="request()->routeIs('admin.*')">
{{ __('Admin') }}
</x-responsive-nav-link>
@endrole
@endauth
</div>
<!-- Responsive Settings Options -->
+5
View File
@@ -20,6 +20,11 @@
<x-primary-button>Save provider profile</x-primary-button>
</form>
@if ($profile)
<section class="rounded border bg-white p-6">
<h3 class="font-semibold">Profile photos and files</h3>
<x-attachments :attachments="$profile->attachments" />
<x-attachment-form type="provider_profile" :id="$profile->id" kind="profile" />
</section>
<form method="POST" action="{{ route('provider-imports.store') }}" class="space-y-4 rounded border bg-white p-6">
@csrf
<h3 class="font-semibold">External profile snapshot</h3>
+1
View File
@@ -12,6 +12,7 @@
<div><dt class="text-sm text-gray-500">Rate card</dt><dd class="whitespace-pre-line">{{ $profile->rate_card }}</dd></div>
<div><dt class="text-sm text-gray-500">Travel policy</dt><dd class="whitespace-pre-line">{{ $profile->travel_policy }}</dd></div>
</dl>
<x-attachments :attachments="$profile->attachments" />
</section>
<section class="rounded border bg-white p-6">
<h3 class="font-semibold">External profile history</h3>
+23 -1
View File
@@ -6,11 +6,13 @@
<p class="mt-4 whitespace-pre-line">{{ $workOrder->agreed_terms }}</p>
<h3 class="mt-6 font-semibold">Deliverables</h3>
<p class="mt-2 whitespace-pre-line">{{ $workOrder->deliverables_checklist }}</p>
<x-attachments :attachments="$workOrder->attachments" />
<x-attachment-form type="work_order" :id="$workOrder->id" kind="work_order" />
<form method="POST" action="{{ route('work-orders.transition', $workOrder) }}" class="mt-6 space-y-4">
@csrf @method('PATCH')
<label class="block text-sm font-medium">Update status</label>
<select name="status" class="rounded-md border-gray-300">
@foreach (\App\Models\WorkOrder::STATUSES as $status)
@foreach (\App\Models\WorkOrder::ALLOWED_TRANSITIONS[$workOrder->status] ?? [] as $status)
<option value="{{ $status }}" @selected($workOrder->status === $status)>{{ str_replace('_', ' ', $status) }}</option>
@endforeach
</select>
@@ -18,17 +20,37 @@
<x-primary-button>Save status</x-primary-button>
</form>
</section>
<section class="rounded border bg-white p-6">
<h3 class="font-semibold">Messages</h3>
<form method="POST" action="{{ route('work-order-messages.store', $workOrder) }}" class="mt-4 space-y-4">
@csrf
<x-field name="body" label="Message" textarea />
<x-primary-button>Send message</x-primary-button>
</form>
@foreach ($workOrder->messages as $message)
<div class="mt-3 rounded bg-gray-50 p-3 text-sm">
<p class="font-semibold">{{ $message->user->name }} | {{ $message->created_at->diffForHumans() }}</p>
<p class="whitespace-pre-line">{{ $message->body }}</p>
</div>
@endforeach
</section>
<section class="rounded border bg-white p-6">
<h3 class="font-semibold">Reviews</h3>
<form method="POST" action="{{ route('reviews.store', $workOrder) }}" class="mt-4 space-y-4">
@csrf
<x-field name="rating" label="Rating 1-5" type="number" />
<x-field name="communication_rating" label="Communication 1-5" type="number" />
<x-field name="scope_accuracy_rating" label="Scope accuracy 1-5" type="number" />
<x-field name="payment_reliability_rating" label="Payment reliability 1-5" type="number" />
<x-field name="workmanship_rating" label="Workmanship 1-5" type="number" />
<x-field name="timeliness_rating" label="Timeliness 1-5" type="number" />
<x-field name="body" label="Review" textarea />
<x-primary-button>Save review</x-primary-button>
</form>
@foreach ($workOrder->reviews as $review)
<div class="mt-4 rounded border p-4 text-sm">
<p class="font-semibold">{{ $review->reviewer->name }} rated {{ $review->reviewee->name }} {{ $review->rating }}/5</p>
<p class="mt-1 text-gray-600">Communication {{ $review->communication_rating ?? 'n/a' }} | Scope {{ $review->scope_accuracy_rating ?? 'n/a' }} | Payment {{ $review->payment_reliability_rating ?? 'n/a' }} | Workmanship {{ $review->workmanship_rating ?? 'n/a' }} | Timeliness {{ $review->timeliness_rating ?? 'n/a' }}</p>
<p class="mt-2 whitespace-pre-line">{{ $review->body }}</p>
</div>
@endforeach