Filament order detail infolist with line items
A read-only order view for Filament 4 using an infolist: status badge, customer block, repeatable item lines and a bold money total.
FilamentLayoutsfilamentinfolistordersview-page
Code
<?php
namespace App\Filament\Resources\Orders\Schemas;
use Filament\Infolists\Components\RepeatableEntry;
use Filament\Infolists\Components\TextEntry;
use Filament\Schemas\Components\Grid;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Filament\Support\Enums\FontWeight;
use Filament\Support\Enums\TextSize;
/** Call from the resource: public static function infolist(Schema $schema): Schema { return OrderInfolist::configure($schema); } */
class OrderInfolist
{
public static function configure(Schema $schema): Schema
{
return $schema->components([
Grid::make(3)->schema([
Section::make('Order')
->columnSpan(2)
->columns(3)
->schema([
TextEntry::make('number')->label('Order #')->copyable()->weight(FontWeight::SemiBold),
TextEntry::make('status')->badge()->color(fn (string $state): string => match ($state) {
'delivered' => 'success',
'cancelled', 'refunded' => 'danger',
'shipped' => 'info',
default => 'warning',
}),
TextEntry::make('placed_at')->dateTime('M j, Y H:i')->since()->tooltip(fn ($record) => $record->placed_at),
]),
Section::make('Customer')
->schema([
TextEntry::make('customer.name'),
TextEntry::make('shipping_address')
->state(fn ($record) => collect([$record->ship_line1, $record->ship_city, $record->ship_country])->filter()->implode(', '))
->placeholder('No address'),
]),
]),
Section::make('Items')->schema([
RepeatableEntry::make('items')
->hiddenLabel()
->columns(4)
->schema([
TextEntry::make('product.name')->columnSpan(2),
TextEntry::make('quantity')->numeric(),
TextEntry::make('unit_price')->money('usd', divideBy: 100)->alignEnd(),
]),
]),
Section::make('Totals')->columns(3)->schema([
TextEntry::make('subtotal')->money('usd', divideBy: 100),
TextEntry::make('shipping_total')->label('Shipping')->money('usd', divideBy: 100),
TextEntry::make('total')->money('usd', divideBy: 100)->size(TextSize::Large)->weight(FontWeight::Bold),
]),
]);
}
}
Needs: filament/filament@^4.0
How it works
What it solves
Order screens are usually read much more than edited. A form-shaped view with disabled inputs looks wrong and wastes space; an infolist presents values as text, badges and tables, and can be reused for both a View page and a modal.
How it works
OrderInfolist::configure() builds a Schema of display components. A three-column Grid puts the order facts in a section that spans two columns and the customer block beside it. Entries read attributes and relations with dot notation, so customer.name and product.name need no custom code.
The status entry is a badge() whose colour comes from a match, so the meaning of colours lives next to the display. The timestamp shows a relative time with since() and the exact moment in a tooltip. The address is computed with state() from several columns, with a placeholder() for missing data.
RepeatableEntry loops over the items relation and renders each line using nested entries. Money is stored in cents and formatted with money('usd', divideBy: 100), and the grand total gets a larger size and bold weight.
Adapting it
Keep the class as a helper and call it from infolist() on the resource. Add actions in section headers, or relation managers below for payments and notes. Replace the currency string with a per-order currency column through a closure.
Pitfalls
- Eager load
items.productandcustomerin the resource'sgetEloquentQuery(), otherwise the repeatable entry issues one query per line. - Infolist entries are not editable. If you need inline edits, use a relation manager.
copyable()needs a secure context (HTTPS) in browsers.
How to use it
- Create a resource with a view page:
php artisan make:filament-resource Order --view. - Put
OrderInfolist.phpin the resource'sSchemasfolder and call it from the resourceinfolist()method. - Make sure the model has
customer()anditems()relations, withproduct()on each item. - Eager load them in
getEloquentQuery(). - Adjust the field names and the currency to your schema.
Licence: DEV3 Snippet Licence. Free to use, change and ship in personal and commercial projects. Attribution is appreciated, not required. Please do not redistribute snippets as a collection.