Skip to content

Commit 2f8d4fc

Browse files
simonhampclaude
andcommitted
Move support tickets to customer dashboard with Livewire components
Migrate support ticket views from public /support/* routes to /dashboard/* using Livewire page components with Flux layout. Fix Filament admin panel class references for this version and restyle the admin ticket replies widget with inline styles. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0815e0a commit 2f8d4fc

21 files changed

Lines changed: 988 additions & 1067 deletions

File tree

app/Filament/Resources/SupportTicketResource.php

Lines changed: 55 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@
55
use App\Filament\Resources\SupportTicketResource\Pages;
66
use App\Models\SupportTicket;
77
use App\SupportTicket\Status;
8+
use Filament\Actions;
89
use Filament\Infolists;
9-
use Filament\Infolists\Infolist;
1010
use Filament\Resources\Resource;
11+
use Filament\Schemas\Components\Section;
12+
use Filament\Schemas\Schema;
1113
use Filament\Tables;
1214
use Filament\Tables\Table;
1315

1416
class SupportTicketResource extends Resource
1517
{
1618
protected static ?string $model = SupportTicket::class;
1719

18-
protected static ?string $navigationIcon = 'heroicon-o-ticket';
20+
protected static \BackedEnum|string|null $navigationIcon = 'heroicon-o-ticket';
1921

2022
protected static ?string $navigationLabel = 'Support Tickets';
2123

@@ -26,59 +28,57 @@ public static function canCreate(): bool
2628
return false;
2729
}
2830

29-
public static function infolist(Infolist $infolist): Infolist
31+
public static function infolist(Schema $schema): Schema
3032
{
31-
return $infolist
33+
return $schema
34+
->columns(2)
3235
->schema([
33-
Infolists\Components\Grid::make(2)
36+
Section::make('Ticket Details')
3437
->schema([
35-
Infolists\Components\Section::make('Ticket Details')
36-
->schema([
37-
Infolists\Components\TextEntry::make('mask')
38-
->label('Ticket ID'),
39-
Infolists\Components\TextEntry::make('status')
40-
->badge()
41-
->color(fn (Status $state): string => match ($state) {
42-
Status::OPEN => 'warning',
43-
Status::IN_PROGRESS => 'info',
44-
Status::ON_HOLD => 'gray',
45-
Status::RESPONDED => 'success',
46-
Status::CLOSED => 'danger',
47-
}),
48-
Infolists\Components\TextEntry::make('product')
49-
->label('Product'),
50-
Infolists\Components\TextEntry::make('issue_type')
51-
->label('Issue Type')
52-
->placeholder('N/A'),
53-
Infolists\Components\TextEntry::make('user.email')
54-
->label('User')
55-
->url(fn (SupportTicket $record): string => UserResource::getUrl('edit', ['record' => $record->user_id])),
56-
Infolists\Components\TextEntry::make('created_at')
57-
->label('Created')
58-
->dateTime(),
59-
Infolists\Components\TextEntry::make('updated_at')
60-
->label('Updated')
61-
->dateTime(),
62-
])
63-
->columns(2)
64-
->collapsible()
65-
->persistCollapsed()
66-
->columnSpan(1),
67-
68-
Infolists\Components\Section::make('Context')
69-
->schema([
70-
Infolists\Components\TextEntry::make('subject')
71-
->label('Subject')
72-
->columnSpanFull(),
73-
Infolists\Components\TextEntry::make('message')
74-
->label('Message')
75-
->markdown()
76-
->columnSpanFull(),
77-
])
78-
->collapsible()
79-
->persistCollapsed()
80-
->columnSpan(1),
81-
]),
38+
Infolists\Components\TextEntry::make('mask')
39+
->label('Ticket ID'),
40+
Infolists\Components\TextEntry::make('status')
41+
->badge()
42+
->color(fn (Status $state): string => match ($state) {
43+
Status::OPEN => 'warning',
44+
Status::IN_PROGRESS => 'info',
45+
Status::ON_HOLD => 'gray',
46+
Status::RESPONDED => 'success',
47+
Status::CLOSED => 'danger',
48+
}),
49+
Infolists\Components\TextEntry::make('product')
50+
->label('Product'),
51+
Infolists\Components\TextEntry::make('issue_type')
52+
->label('Issue Type')
53+
->placeholder('N/A'),
54+
Infolists\Components\TextEntry::make('user.email')
55+
->label('User')
56+
->url(fn (SupportTicket $record): string => UserResource::getUrl('edit', ['record' => $record->user_id])),
57+
Infolists\Components\TextEntry::make('created_at')
58+
->label('Created')
59+
->dateTime(),
60+
Infolists\Components\TextEntry::make('updated_at')
61+
->label('Updated')
62+
->dateTime(),
63+
])
64+
->columns(2)
65+
->collapsible()
66+
->persistCollapsed()
67+
->columnSpan(1),
68+
69+
Section::make('Context')
70+
->schema([
71+
Infolists\Components\TextEntry::make('subject')
72+
->label('Subject')
73+
->columnSpanFull(),
74+
Infolists\Components\TextEntry::make('message')
75+
->label('Message')
76+
->markdown()
77+
->columnSpanFull(),
78+
])
79+
->collapsible()
80+
->persistCollapsed()
81+
->columnSpan(1),
8282
]);
8383
}
8484

@@ -132,11 +132,11 @@ public static function table(Table $table): Table
132132
]),
133133
])
134134
->actions([
135-
Tables\Actions\ViewAction::make(),
135+
Actions\ViewAction::make(),
136136
])
137137
->bulkActions([
138-
Tables\Actions\BulkActionGroup::make([
139-
Tables\Actions\DeleteBulkAction::make(),
138+
Actions\BulkActionGroup::make([
139+
Actions\DeleteBulkAction::make(),
140140
]),
141141
])
142142
->defaultSort('created_at', 'desc');

app/Filament/Resources/SupportTicketResource/RelationManagers/RepliesRelationManager.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
use App\Models\SupportTicket\Reply;
66
use App\Notifications\SupportTicketReplied;
77
use Filament\Forms;
8-
use Filament\Forms\Form;
98
use Filament\Resources\RelationManagers\RelationManager;
9+
use Filament\Schemas\Schema;
1010
use Filament\Tables;
1111
use Filament\Tables\Table;
1212

@@ -23,9 +23,9 @@ public function isReadOnly(): bool
2323
return false;
2424
}
2525

26-
public function form(Form $form): Form
26+
public function form(Schema $schema): Schema
2727
{
28-
return $form
28+
return $schema
2929
->schema([
3030
Forms\Components\Textarea::make('message')
3131
->required()

app/Filament/Resources/SupportTicketResource/Widgets/TicketRepliesWidget.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
class TicketRepliesWidget extends Widget
1010
{
11-
protected static string $view = 'filament.resources.support-ticket-resource.widgets.ticket-replies';
11+
protected string $view = 'filament.resources.support-ticket-resource.widgets.ticket-replies';
1212

1313
public ?Model $record = null;
1414

app/Http/Controllers/Account/Support/TicketController.php

Lines changed: 0 additions & 71 deletions
This file was deleted.
Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
<?php
22

3-
namespace App\Livewire;
3+
namespace App\Livewire\Customer\Support;
44

55
use App\Models\Plugin;
66
use App\Models\SupportTicket;
77
use App\Notifications\SupportTicketSubmitted;
88
use App\SupportTicket\Status;
99
use Illuminate\Support\Facades\Notification;
1010
use Illuminate\Support\Str;
11+
use Livewire\Attributes\Layout;
1112
use Livewire\Attributes\Locked;
13+
use Livewire\Attributes\Title;
1214
use Livewire\Component;
1315

14-
class CreateSupportTicket extends Component
16+
#[Layout('components.layouts.dashboard')]
17+
#[Title('Submit a Request')]
18+
class Create extends Component
1519
{
1620
#[Locked]
1721
public int $currentStep = 1;
@@ -133,7 +137,7 @@ public function submit(): void
133137
Notification::route('mail', 'support@nativephp.com')
134138
->notify(new SupportTicketSubmitted($ticket));
135139

136-
$this->redirect(route('support.tickets.show', $ticket), navigate: false);
140+
$this->redirect(route('customer.support.tickets.show', $ticket), navigate: false);
137141
}
138142

139143
protected function validateStep1(): void
@@ -203,8 +207,8 @@ public function render()
203207
->pluck('name', 'id');
204208
}
205209

206-
return view('livewire.create-support-ticket', [
210+
return view('livewire.customer.support.create', [
207211
'officialPlugins' => $officialPlugins,
208-
])->layout('components.layout', ['title' => 'Submit a Request - NativePHP']);
212+
]);
209213
}
210214
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace App\Livewire\Customer\Support;
4+
5+
use App\Models\SupportTicket;
6+
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
7+
use Illuminate\Contracts\View\View;
8+
use Livewire\Attributes\Computed;
9+
use Livewire\Attributes\Layout;
10+
use Livewire\Attributes\Title;
11+
use Livewire\Component;
12+
use Livewire\WithPagination;
13+
14+
#[Layout('components.layouts.dashboard')]
15+
#[Title('Support Tickets')]
16+
class Index extends Component
17+
{
18+
use WithPagination;
19+
20+
#[Computed]
21+
public function supportTickets(): LengthAwarePaginator
22+
{
23+
return SupportTicket::where('user_id', auth()->id())
24+
->orderBy('status', 'desc')
25+
->orderBy('created_at', 'desc')
26+
->paginate(10);
27+
}
28+
29+
public function render(): View
30+
{
31+
return view('livewire.customer.support.index');
32+
}
33+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
namespace App\Livewire\Customer\Support;
4+
5+
use App\Models\SupportTicket;
6+
use App\Notifications\SupportTicketUserReplied;
7+
use App\SupportTicket\Status;
8+
use Illuminate\Contracts\View\View;
9+
use Illuminate\Support\Facades\Notification;
10+
use Livewire\Attributes\Layout;
11+
use Livewire\Attributes\Title;
12+
use Livewire\Component;
13+
14+
#[Layout('components.layouts.dashboard')]
15+
#[Title('Support Ticket')]
16+
class Show extends Component
17+
{
18+
public SupportTicket $supportTicket;
19+
20+
public string $replyMessage = '';
21+
22+
public function mount(SupportTicket $supportTicket): void
23+
{
24+
$this->authorize('view', $supportTicket);
25+
26+
$supportTicket->load(['user', 'replies.user']);
27+
28+
$this->supportTicket = $supportTicket;
29+
}
30+
31+
public function reply(): void
32+
{
33+
$this->authorize('reply', $this->supportTicket);
34+
35+
$this->validate([
36+
'replyMessage' => ['required', 'string', 'max:5000'],
37+
]);
38+
39+
$reply = $this->supportTicket->replies()->create([
40+
'user_id' => auth()->id(),
41+
'message' => $this->replyMessage,
42+
'note' => false,
43+
]);
44+
45+
Notification::route('mail', 'support@nativephp.com')
46+
->notify(new SupportTicketUserReplied($this->supportTicket, $reply));
47+
48+
$this->replyMessage = '';
49+
$this->supportTicket->load(['user', 'replies.user']);
50+
51+
session()->flash('success', 'Your reply has been sent.');
52+
}
53+
54+
public function closeTicket(): void
55+
{
56+
$this->authorize('closeTicket', $this->supportTicket);
57+
58+
$this->supportTicket->update([
59+
'status' => Status::CLOSED,
60+
]);
61+
62+
session()->flash('success', __('account.support_ticket.close_ticket.success'));
63+
}
64+
65+
public function render(): View
66+
{
67+
return view('livewire.customer.support.show');
68+
}
69+
}

0 commit comments

Comments
 (0)