Files
Virtnet.bond/extensions/Others/SocialBase/Admin/Resources/ConversationResource.php
2025-11-30 11:57:22 +01:00

240 lines
9.5 KiB
PHP

<?php
namespace Paymenter\Extensions\Others\SocialBase\Admin\Resources;
use Filament\Resources\Resource;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Tables;
use Filament\Tables\Table;
use Paymenter\Extensions\Others\SocialBase\Models\Conversation;
use Paymenter\Extensions\Others\SocialBase\Admin\Clusters\MessagingCluster;
use Illuminate\Support\HtmlString;
class ConversationResource extends Resource
{
protected static ?string $model = Conversation::class;
protected static ?string $navigationIcon = 'heroicon-o-chat';
protected static ?string $navigationLabel = 'Conversations';
protected static ?string $cluster = MessagingCluster::class;
protected static ?int $navigationSort = 3;
public static function form(Form $form): Form
{
return $form->schema([
Forms\Components\TextInput::make('id')
->label('Conversation ID')
->disabled(),
Forms\Components\TextInput::make('type')
->label('Type')
->afterStateHydrated(function ($component, $state, $record) {
if ($record) {
$component->state(ucfirst($record->type));
}
})
->disabled(),
Forms\Components\TextInput::make('subject')
->label('Subject')
->disabled(),
Forms\Components\Textarea::make('participants_list')
->label('Participants')
->afterStateHydrated(function ($component, $state, $record) {
if (!$record) {
$component->state('—');
return;
}
$participants = $record->participants()->get();
$names = $participants->map(fn($p) => $p->name . ' (' . $p->email . ')')->join("\n");
$component->state($names);
})
->disabled()
->rows(3),
Forms\Components\TextInput::make('created_at')
->label('Created At')
->afterStateHydrated(function ($component, $state, $record) {
if ($record) {
$component->state($record->created_at->format('M j, Y g:i A'));
}
})
->disabled(),
Forms\Components\TextInput::make('last_message_at')
->label('Last Message')
->afterStateHydrated(function ($component, $state, $record) {
if ($record && $record->last_message_at) {
$component->state($record->last_message_at->format('M j, Y g:i A'));
} else {
$component->state('—');
}
})
->disabled(),
Forms\Components\TextInput::make('messages_count')
->label('Total Messages')
->afterStateHydrated(function ($component, $record) {
if ($record) {
$component->state($record->messages()->count());
}
})
->disabled(),
Forms\Components\Placeholder::make('view_messages_link')
->label('View Messages')
->content(function ($record) {
if (!$record) return '—';
$baseUrl = \Paymenter\Extensions\Others\SocialBase\Admin\Resources\MessageModerationResource::getUrl('index');
$url = $baseUrl . '?filters[conversation_id][value]=' . $record->id;
return new HtmlString(
'<a href="' . e($url) . '" class="inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors">' .
'<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">' .
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z"></path>' .
'</svg>' .
'View All ' . $record->messages()->count() . ' Messages' .
'</a>'
);
}),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')
->label('ID')
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('type')
->label('Type')
->badge()
->color(fn(string $state): string => match ($state) {
'direct' => 'success',
'system' => 'info',
default => 'gray',
})
->formatStateUsing(fn(string $state): string => ucfirst($state))
->sortable(),
Tables\Columns\TextColumn::make('participants_names')
->label('Participants')
->getStateUsing(function ($record) {
$participants = $record->participants()->get();
return $participants->map(fn($p) => $p->name)->join(', ');
})
->searchable()
->wrap(),
Tables\Columns\TextColumn::make('messages_count')
->label('Messages')
->counts('messages')
->sortable(),
Tables\Columns\TextColumn::make('flagged_messages_count')
->label('Flagged')
->getStateUsing(function ($record) {
return $record->messages()->where('moderation_status', 'flagged')->count();
})
->badge()
->color(fn($state) => $state > 0 ? 'danger' : 'success')
->sortable(),
Tables\Columns\TextColumn::make('last_message_at')
->label('Last Message')
->dateTime('M j, Y g:i A')
->sortable()
->default('—'),
Tables\Columns\TextColumn::make('created_at')
->label('Created')
->dateTime('M j, Y')
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\SelectFilter::make('type')
->label('Type')
->options([
'direct' => 'Direct',
'system' => 'System',
]),
Tables\Filters\Filter::make('has_messages')
->label('Has Messages')
->query(fn($query) => $query->has('messages')),
Tables\Filters\Filter::make('has_flagged_messages')
->label('Has Flagged Messages')
->query(fn($query) => $query->whereHas('messages', function ($q) {
$q->where('moderation_status', 'flagged');
})),
Tables\Filters\Filter::make('recent_activity')
->label('Recent Activity (24h)')
->query(fn($query) => $query->where('last_message_at', '>=', now()->subDay())),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make()
->before(function ($record) {
$record->messages()->delete();
$record->participants()->detach();
})
->successNotificationTitle('Conversation deleted'),
])
->bulkActions([
Tables\Actions\DeleteBulkAction::make()
->before(function ($records) {
foreach ($records as $record) {
$record->messages()->delete();
$record->participants()->detach();
}
})
->successNotificationTitle('Conversations deleted'),
])
->defaultSort('last_message_at', 'desc')
->poll('30s');
}
public static function getPages(): array
{
return [
'index' => \Paymenter\Extensions\Others\SocialBase\Admin\Resources\ConversationResource\Pages\ListConversations::route('/'),
'view' => \Paymenter\Extensions\Others\SocialBase\Admin\Resources\ConversationResource\Pages\ViewConversation::route('/{record}'),
];
}
public static function canCreate(): bool
{
return false;
}
public static function canEdit($record): bool
{
return false;
}
public static function getNavigationBadge(): ?string
{
$count = static::getModel()::whereHas('messages', function ($query) {
$query->where('moderation_status', 'flagged');
})->count();
return $count > 0 ? (string)$count : null;
}
public static function getNavigationBadgeColor(): ?string
{
$count = static::getModel()::whereHas('messages', function ($query) {
$query->where('moderation_status', 'flagged');
})->count();
return $count > 3 ? 'danger' : ($count > 0 ? 'warning' : null);
}
}