240 lines
9.5 KiB
PHP
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);
|
|
}
|
|
}
|