[IP-221]: client detail view#577
Draft
nielsdrost7 wants to merge 9 commits into
Draft
Conversation
…ion managers New ViewRelation page (Modules/Clients/.../Pages/ViewRelation.php): - Extends Filament\Resources\Pages\ViewRecord - Header actions: Create Invoice (InvoicePlane#217), Create Quote (InvoicePlane#218), Edit - Registered as 'view' => ViewRelation::route('/{record}') in RelationResource Infolist on RelationResource (client summary section): - 9-field 3-column grid: company_name, trading_name, relation_number, relation_type (badge), relation_status (badge), registered_at, coc_number, vat_number, currency_code Five RelationManagers (tabs on the view page): - InvoicesRelationManager: invoice list + Create Invoice header action - QuotesRelationManager: quote list + Create Quote header action - ExpensesRelationManager: expense list (vendor expenses for this client) - TasksRelationManager: task list - ProjectsRelationManager: project list All five relation managers use existing hasMany relationships already defined on the Relation model (invoices, quotes, expenses, tasks, projects). RelationsTable: add ViewAction row button + import Action/ViewAction/ InvoiceResource/QuoteResource + Create Invoice and Create Quote row actions (the visible entry points from the client list for InvoicePlane#191 and InvoicePlane#192). Fixes InvoicePlane#221 Fixes InvoicePlane#217 Fixes InvoicePlane#218 https://claude.ai/code/session_01L9apN3AW7b5h7ypmBA5pUg
…ns to client detail page Add EditAction to the ViewRelation header (opens edit form). Add conditional DeleteAction that is hidden when the client has any linked invoices, quotes, expenses, tasks, or projects (InvoicePlane#220). Service-layer guard in RelationService throws RelationHasLinkedRecordsException as a backstop for direct API calls. https://claude.ai/code/session_01L9apN3AW7b5h7ypmBA5pUg
… tests for client detail view page Tests verify: - ViewRelation page renders without errors - RelationService::deleteRelation() throws RelationHasLinkedRecordsException when the client has linked invoices or quotes - Clients without linked records can be deleted successfully https://claude.ai/code/session_01L9apN3AW7b5h7ypmBA5pUg
…fill customer from URL
- Register 'create' => CreateInvoice::route('/create') in InvoiceResource::getPages()
so the create form is accessible via a URL (was defined but unreachable)
- Override mount() in CreateInvoice to read ?customer_id= query param and
pre-fill the form via $this->form->fill(['customer_id' => ...])
- Override mutateFormDataBeforeCreate() to ensure the query param survives
form submission even if Livewire rehydrates the form state
The row-level "Create Invoice" button on the client list (RelationsTable)
is wired up in the InvoicePlane#221 client-detail-view PR, which adds the full suite
of client actions.
Fixes InvoicePlane#191
https://claude.ai/code/session_01L9apN3AW7b5h7ypmBA5pUg
…ll customer from URL
- Register 'create' => CreateQuote::route('/create') in QuoteResource::getPages()
so the create form is accessible via a URL (was defined but unreachable)
- Override mount() in CreateQuote to read ?customer_id= query param and
pre-fill the form via $this->form->fill(['customer_id' => ...])
- Override mutateFormDataBeforeCreate() to ensure the query param survives
form submission even if Livewire rehydrates the form state
The row-level "Create Quote" button on the client list (RelationsTable)
is wired up in the InvoicePlane#221 client-detail-view PR.
Fixes InvoicePlane#192
https://claude.ai/code/session_01L9apN3AW7b5h7ypmBA5pUg
…mer_id query param The quote form's client field is prospect_id; filling customer_id left the pre-selection silently empty. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…): gate client list row actions and guard delete Create Invoice is visible only for customer-type relations with the create-invoices permission; Create Quote for any type with the create-quotes permission. The list DeleteAction is hidden when the relation has linked records and surfaces a notification instead of a 500 if the service guard trips anyway. Extract Relation::hasLinkedRecords() and reuse it in the service guard, ViewRelation, and the table; the shared check now also covers payments. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…): cover client list row actions and prefill Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #221
Closes #217
Closes #218
What was missing
Clients had no detail/view page. The list was the only entry point, with only Edit and Delete actions.
Changes
ViewRelation page (
Pages/ViewRelation.php)Filament\Resources\Pages\ViewRecord'view' => ViewRelation::route('/{record}')in RelationResourceInfolist on RelationResource
9-field client summary in a 3-column grid:
company_name,trading_name,relation_number,relation_type(badge),relation_status(badge),registered_at,coc_number,vat_number,currency_codeFive RelationManagers (tabs)
InvoicesRelationManagerinvoices(customer_id)QuotesRelationManagerquotes(prospect_id)ExpensesRelationManagerexpenses(vendor_id)TasksRelationManagertasks(customer_id)ProjectsRelationManagerprojects(customer_id)All relationships were already defined on the
Relationmodel — no model changes needed.RelationsTable
ViewActionrow button (navigates to the view page)Action::make('create_invoice')andAction::make('create_quote')row actions pointing to the create pages (from PRs [Clients]: Create a quote for a specific client from the client list #191 and [Clients]: Create an invoice for a specific client from the client list #192) with?customer_id=pre-fillCloses #191
Closes #192
Summary by CodeRabbit
New Features
Bug Fixes
Tests
Update 2026-07-03 (session continuation)
createpages and pre-fills the client from?customer_id=.prospect_id, notcustomer_id([Clients]: Create an invoice for a specific client from the client list #192).create-invoices; Create Quote for all types withcreate-quotes.Relation::hasLinkedRecords()shared by the table,ViewRelation, and the service guard; the check now also covers payments.RelationListRowActionsTest(5 tests) covering action visibility, delete guard, and both prefills.Issues covered by this PR: #221, #217, #218, #219, #220, #29, #191, #192.