Skip to content

Commit 0c3adee

Browse files
Addition of a RelationManager for the tenant manager to view the WhatsApp instances of each tenant.
1 parent 27099a6 commit 0c3adee

File tree

7 files changed

+447
-106
lines changed

7 files changed

+447
-106
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ yarn-error.log
2222
/.vscode
2323
/.zed
2424
.docker
25-
.docker-compose copy.yml
25+
docker-compose.yml
26+
old_docker-compose.yml

app/Filament/Admin/Resources/OrganizationResource.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use App\Enums\Stripe\{ProductIntervalEnum, SubscriptionStatusEnum};
66
use App\Filament\Admin\Resources\OrganizationResource\Pages;
7-
use App\Filament\Admin\Resources\OrganizationResource\RelationManagers\{SubscriptionRefundsRelationManager, SubscriptionRelationManager, UserRelationManager};
7+
use App\Filament\Admin\Resources\OrganizationResource\RelationManagers\{SubscriptionRefundsRelationManager, SubscriptionRelationManager, UserRelationManager, WhatsappInstanceRelationManager};
88
use App\Models\{Organization, Price};
99
use Filament\Forms\Components\{Fieldset, Grid, TextInput};
1010
use Filament\Forms\{Form, Set};
@@ -287,6 +287,7 @@ public static function getRelations(): array
287287
UserRelationManager::class,
288288
SubscriptionRelationManager::class,
289289
SubscriptionRefundsRelationManager::class,
290+
WhatsappInstanceRelationManager::class,
290291
];
291292
}
292293

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
<?php
2+
3+
namespace App\Filament\Admin\Resources\OrganizationResource\RelationManagers;
4+
5+
use App\Models\WhatsappInstance;
6+
use App\Services\Evolution\Instance\{ConnectEvolutionInstanceService, DeleteEvolutionInstanceService, FetchEvolutionInstanceService, LogOutEvolutionInstanceService, RestartEvolutionInstanceService};
7+
use App\Services\Evolution\Message\SendMessageEvolutionService;
8+
use Filament\Facades\Filament;
9+
use Filament\Forms\Components\{Fieldset, Section, TextInput, ToggleButtons};
10+
use Filament\Forms\Form;
11+
use Filament\Notifications\Notification;
12+
use Filament\Resources\RelationManagers\RelationManager;
13+
use Filament\Tables\Actions\{Action, ActionGroup, DeleteAction, EditAction, ViewAction};
14+
use Filament\Tables\Columns\{ImageColumn, TextColumn};
15+
use Filament\Tables\Table;
16+
use Filament\{Tables};
17+
use Leandrocfe\FilamentPtbrFormFields\PhoneNumber;
18+
19+
class WhatsappInstanceRelationManager extends RelationManager
20+
{
21+
protected static string $relationship = 'whatsappInstances';
22+
23+
protected static ?string $modelLabel = 'Instância do WhatsApp';
24+
25+
protected static ?string $modelLabelPlural = "Instâncias do WhatsApp";
26+
27+
protected static ?string $title = 'Instâncias do WhatsApp';
28+
29+
public function form(Form $form): Form
30+
{
31+
return $form
32+
->schema([
33+
Section::make('Dados da Instância')
34+
->schema([
35+
36+
TextInput::make('name')
37+
->label('Nome da Instância')
38+
->unique(WhatsappInstance::class, 'name', ignoreRecord: true)
39+
->default(fn () => Filament::getTenant()?->slug ?? '')
40+
->required()
41+
->prefixIcon('fas-id-card')
42+
->validationMessages([
43+
'unique' => 'Nome da instância já cadastrada.',
44+
])
45+
->maxLength(20),
46+
47+
PhoneNumber::make('number')
48+
->label('Número WhatsApp')
49+
->unique(WhatsappInstance::class, 'number', ignoreRecord: true)
50+
->mask('+55 (99) 99999-9999')
51+
->placeholder('+55 (99) 99999-9999')
52+
->required()
53+
->prefixIcon('fab-whatsapp')
54+
->validationMessages([
55+
'unique' => 'Número já cadastrado.',
56+
]),
57+
58+
])->columns(2),
59+
60+
Section::make('Dados da Instância')
61+
->schema([
62+
ToggleButtons::make('groups_ignore')
63+
->label('Ignorar Grupos')
64+
->inline()
65+
->boolean()
66+
->required(),
67+
68+
ToggleButtons::make('always_online')
69+
->label('Sempre Online')
70+
->inline()
71+
->boolean()
72+
->required(),
73+
74+
ToggleButtons::make('read_messages')
75+
->label('Mensagens como Lidas')
76+
->inline()
77+
->boolean()
78+
->required(),
79+
80+
ToggleButtons::make('read_status')
81+
->label('Status como Lido')
82+
->inline()
83+
->boolean()
84+
->required(),
85+
86+
ToggleButtons::make('sync_full_history')
87+
->label('Sincronizar Histórico')
88+
->inline()
89+
->boolean()
90+
->required(),
91+
92+
ToggleButtons::make('reject_call')
93+
->label('Rejeitar Chamadas')
94+
->inline()
95+
->boolean()
96+
->live()
97+
->reactive()
98+
->required(),
99+
100+
TextInput::make('msg_call')
101+
->label('Mensagem para Chamadas Rejeitadas')
102+
->required()
103+
->hidden(fn ($get) => $get('reject_call') == false)
104+
->maxLength(255),
105+
106+
])->columns(4),
107+
]);
108+
}
109+
110+
public function table(Table $table): Table
111+
{
112+
return $table
113+
->columns([
114+
ImageColumn::make('profile_picture_url')
115+
->label('Imagem de Perfil')
116+
->alignCenter()
117+
->circular()
118+
->getStateUsing(fn ($record) => $record->profile_picture_url ?: 'https://www.cidademarketing.com.br/marketing/wp-content/uploads/2018/12/whatsapp-640x640.png'),
119+
120+
TextColumn::make('status')
121+
->label('Status')
122+
->alignCenter()
123+
->badge()
124+
->searchable(),
125+
126+
TextColumn::make('name')
127+
->label('Nome da Instância')
128+
->searchable(),
129+
130+
TextColumn::make('number')
131+
->label('Número')
132+
->searchable(),
133+
134+
TextColumn::make('instance_id')
135+
->label('ID da Instância')
136+
->searchable(),
137+
138+
TextColumn::make('created_at')
139+
->dateTime()
140+
->sortable()
141+
->toggleable(isToggledHiddenByDefault: true),
142+
143+
TextColumn::make('updated_at')
144+
->dateTime()
145+
->sortable()
146+
->toggleable(isToggledHiddenByDefault: true),
147+
])
148+
->filters([
149+
//
150+
])
151+
->actions([
152+
Action::make('showQr')
153+
->hidden(fn ($record) => $record->status->value === 'open')
154+
->label('QR Code')
155+
->icon('heroicon-o-qr-code')
156+
->color('success')
157+
->modalHeading('Qr Code WhatsApp')
158+
->modalSubmitAction(false)
159+
->modalCancelAction(
160+
\Filament\Actions\Action::make('close')
161+
->label('FECHAR')
162+
->color('danger') // Cores: primary, secondary, success, danger, warning, gray
163+
->extraAttributes(['class' => 'w-full']) // Largura total
164+
->close()
165+
)
166+
->modalWidth('md') // ou sm, lg, xl, 2xl, 3xl, 4xl, 5xl, 6xl, 7xl
167+
->modalContent(fn ($record) => view('evolution.qr-code-modal', [
168+
'qrCode' => str_replace('\/', '/', $record->getRawOriginal('qr_code')),
169+
])),
170+
171+
ActionGroup::make([
172+
Action::make('RestartInstance')
173+
->label('Reiniciar Instância')
174+
->hidden(fn ($record) => $record->status->value === 'close')
175+
->icon('fas-rotate-right')
176+
->color('warning')
177+
->action(function ($record, $livewire) {
178+
$service = new RestartEvolutionInstanceService();
179+
$response = $service->restartInstance($record->name);
180+
181+
if (isset($response['error'])) {
182+
Notification::make()
183+
->title('Erro ao reiniciar')
184+
->danger()
185+
->send();
186+
} else {
187+
Notification::make()
188+
->title('Instância reiniciada')
189+
->success()
190+
->send();
191+
}
192+
$livewire->dispatch('refresh');
193+
}),
194+
195+
Action::make('LogoutInstance')
196+
->hidden(fn ($record) => $record->status->value !== 'open')
197+
->label('Desconectar Instância')
198+
->icon('fas-sign-out-alt')
199+
->color('danger')
200+
->action(function ($record, $livewire) {
201+
$service = new LogOutEvolutionInstanceService();
202+
$response = $service->logoutInstance($record->name);
203+
204+
if (!empty($response['error'])) {
205+
Notification::make()
206+
->title('Erro ao desconectar')
207+
->danger()
208+
->send();
209+
} else {
210+
Notification::make()
211+
->title('Instância desconectada')
212+
->body('Faça login novamente e escaneie o QR Code')
213+
->success()
214+
->send();
215+
}
216+
$livewire->dispatch('refresh');
217+
}),
218+
219+
Action::make('ConectInstance')
220+
->hidden(fn ($record) => $record->status->value === 'open')
221+
->label('Conectar Instância')
222+
->icon('fas-sign-in-alt')
223+
->color('info')
224+
->action(function ($record, $livewire) {
225+
$service = new ConnectEvolutionInstanceService();
226+
$response = $service->connectInstance($record->name);
227+
228+
if (isset($response['error'])) {
229+
Notification::make()
230+
->title('Erro ao reconectar')
231+
->danger()
232+
->send();
233+
} else {
234+
Notification::make()
235+
->title('Instância reconectada')
236+
->body('Leia o QRcode para Ativar Sincronização dos dados')
237+
->success()
238+
->send();
239+
}
240+
$livewire->dispatch('refresh');
241+
}),
242+
243+
Action::make('syncInstance')
244+
->label('Sincronizar Dados')
245+
->icon('fas-sync')
246+
->color('info')
247+
->action(function ($record, $livewire) {
248+
$service = new FetchEvolutionInstanceService();
249+
$response = $service->fetchInstance($record->name);
250+
251+
if (isset($response['error'])) {
252+
Notification::make()
253+
->title('Erro ao sincronizar dados')
254+
->danger()
255+
->send();
256+
} else {
257+
Notification::make()
258+
->title('Instância sincronizada')
259+
->body('Dados sincronizados com sucesso')
260+
->success()
261+
->send();
262+
}
263+
// Fecha o ActionGroup
264+
$livewire->dispatch('close-modal');
265+
$livewire->dispatch('refresh');
266+
}),
267+
268+
Action::make('Enviar Mensagem')
269+
->requiresConfirmation()
270+
->hidden(fn ($record) => $record->status->value !== 'open')
271+
->form([
272+
Fieldset::make('Envie sua mensagem')
273+
->schema([
274+
PhoneNumber::make('number_whatsapp')
275+
->label('Número WhatsApp')
276+
->mask('+55 (99) 99999-9999')
277+
->placeholder('+55 (99) 99999-9999')
278+
->required()
279+
->prefixIcon('fab-whatsapp'),
280+
281+
TextInput::make('message')
282+
->label('Mensagem'),
283+
284+
])->columns(1),
285+
])
286+
287+
->modalHeading('Enviar Mensagem')
288+
->modalDescription('Envie uma de teste para validar o serviço')
289+
->color('success')
290+
->icon('fab-whatsapp')
291+
->action(function (Action $action, $record, array $data, $livewire) {
292+
try {
293+
$service = new SendMessageEvolutionService();
294+
$service->sendMessage($record->name, $data);
295+
296+
Notification::make()
297+
->title('Mensagem enviada')
298+
->body('Mensagem enviada com Sucesso')
299+
->success()
300+
->send();
301+
} catch (\Exception $e) {
302+
Notification::make()
303+
->title('Erro ao enviar mensagem')
304+
->body('Ocorreu um erro ao enviar mensagem: ' . $e->getMessage())
305+
->danger()
306+
->send();
307+
}
308+
$livewire->dispatch('refresh');
309+
})
310+
->icon('fab-whatsapp')
311+
->color('success'),
312+
])
313+
->icon('fab-whatsapp')
314+
->color('success'),
315+
316+
ActionGroup::make([
317+
ViewAction::make()
318+
->color('primary'),
319+
EditAction::make()
320+
->color('secondary'),
321+
DeleteAction::make()
322+
->action(function ($record, $livewire) {
323+
$service = new DeleteEvolutionInstanceService();
324+
$response = $service->deleteInstance($record->name);
325+
326+
// Deleta o registro local após sucesso na API
327+
$record->delete();
328+
$livewire->dispatch('refresh');
329+
}),
330+
])
331+
->icon('fas-sliders')
332+
->color('warning'),
333+
])
334+
->bulkActions([
335+
Tables\Actions\BulkActionGroup::make([
336+
Tables\Actions\DeleteBulkAction::make(),
337+
]),
338+
]);
339+
}
340+
}

0 commit comments

Comments
 (0)