feat: implement intern blog management system with approval workflows and administrative feedback
This commit is contained in:
@@ -2,11 +2,14 @@
|
||||
|
||||
namespace App\Filament\Admin\Resources\Blogs\Tables;
|
||||
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Tables\Columns\ImageColumn;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Columns\ToggleColumn;
|
||||
@@ -32,26 +35,45 @@ class BlogsTable
|
||||
->sortable()
|
||||
->limit(50),
|
||||
|
||||
TextColumn::make('slug')
|
||||
->label(__('blog.table_slug'))
|
||||
->searchable()
|
||||
->sortable()
|
||||
->limit(30),
|
||||
|
||||
TextColumn::make('status')
|
||||
->label(__('blog.table_status'))
|
||||
->badge()
|
||||
->color(fn (string $state): string => match ($state) {
|
||||
->color(fn (?string $state): string => match ($state) {
|
||||
'draft' => 'gray',
|
||||
'pending' => 'info',
|
||||
'published' => 'success',
|
||||
'rejected' => 'danger',
|
||||
'archived' => 'warning',
|
||||
default => 'gray',
|
||||
})
|
||||
->formatStateUsing(fn (string $state): string => match ($state) {
|
||||
'draft' => __('blog.status_draft'),
|
||||
'published' => __('blog.status_published'),
|
||||
'archived' => __('blog.status_archived'),
|
||||
->formatStateUsing(fn (?string $state): string => match ($state) {
|
||||
'draft' => 'Taslak',
|
||||
'pending' => 'Onay Bekliyor',
|
||||
'published' => 'Yayınlandı',
|
||||
'rejected' => 'Revize İstendi',
|
||||
'archived' => 'Arşivlendi',
|
||||
default => $state ?? '-',
|
||||
}),
|
||||
|
||||
TextColumn::make('careerApplication.name')
|
||||
->label('Stajyer')
|
||||
->searchable()
|
||||
->sortable()
|
||||
->badge()
|
||||
->color('purple')
|
||||
->toggleable(),
|
||||
|
||||
TextColumn::make('intern_category')
|
||||
->label('Staj Konusu')
|
||||
->formatStateUsing(fn (?string $state): string => match ($state) {
|
||||
'experience' => '1. Staj Tecrübesi',
|
||||
'technical_challenge' => '2. Teknik Zorluklar',
|
||||
'product_showcase' => '3. Ürün Tanıtımı',
|
||||
default => $state ?? '-',
|
||||
})
|
||||
->badge()
|
||||
->toggleable(),
|
||||
|
||||
TextColumn::make('author.name')
|
||||
->label(__('blog.table_author'))
|
||||
->searchable()
|
||||
@@ -75,39 +97,79 @@ class BlogsTable
|
||||
ToggleColumn::make('is_featured')
|
||||
->label(__('blog.is_featured_field'))
|
||||
->alignCenter(),
|
||||
|
||||
TextColumn::make('created_at')
|
||||
->label(__('blog.table_created_at'))
|
||||
->dateTime('d.m.Y H:i')
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
|
||||
TextColumn::make('updated_at')
|
||||
->label(__('blog.table_updated_at'))
|
||||
->dateTime('d.m.Y H:i')
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
SelectFilter::make('status')
|
||||
->label(__('blog.status_field'))
|
||||
->options([
|
||||
'draft' => __('blog.status_draft'),
|
||||
'published' => __('blog.status_published'),
|
||||
'archived' => __('blog.status_archived'),
|
||||
'draft' => 'Taslak',
|
||||
'pending' => 'Onay Bekliyor',
|
||||
'published' => 'Yayınlandı',
|
||||
'rejected' => 'Revize İstendi',
|
||||
'archived' => 'Arşivlendi',
|
||||
]),
|
||||
|
||||
SelectFilter::make('intern_category')
|
||||
->label('Staj Blog Konusu')
|
||||
->options([
|
||||
'experience' => '1. Staj Tecrübesi',
|
||||
'technical_challenge' => '2. Teknik Zorluklar',
|
||||
'product_showcase' => '3. Ürün Tanıtımı',
|
||||
]),
|
||||
|
||||
TernaryFilter::make('is_intern_blog')
|
||||
->label('Sadece Stajyer Yazıları')
|
||||
->queries(
|
||||
true: fn ($query) => $query->whereNotNull('career_application_id'),
|
||||
false: fn ($query) => $query->whereNull('career_application_id'),
|
||||
),
|
||||
|
||||
SelectFilter::make('category_id')
|
||||
->label(__('blog.category_field'))
|
||||
->relationship('category', 'name'),
|
||||
|
||||
TernaryFilter::make('is_featured')
|
||||
->label(__('blog.is_featured_field')),
|
||||
|
||||
TernaryFilter::make('allow_comments')
|
||||
->label(__('blog.allow_comments_field')),
|
||||
])
|
||||
->recordActions([
|
||||
Action::make('approve')
|
||||
->label('Onayla & Yayınla')
|
||||
->icon('heroicon-o-check-circle')
|
||||
->color('success')
|
||||
->visible(fn ($record) => in_array($record->status, ['pending', 'draft', 'rejected']))
|
||||
->action(function ($record) {
|
||||
$record->status = 'published';
|
||||
$record->published_at = now();
|
||||
$record->admin_feedback = null;
|
||||
$record->save();
|
||||
|
||||
Notification::make()
|
||||
->title('Yazı Onaylandı')
|
||||
->body('Blog yazısı başarıyla yayınlandı.')
|
||||
->success()
|
||||
->send();
|
||||
}),
|
||||
|
||||
Action::make('reject')
|
||||
->label('Revize İstə')
|
||||
->icon('heroicon-o-x-circle')
|
||||
->color('danger')
|
||||
->visible(fn ($record) => in_array($record->status, ['pending', 'published']))
|
||||
->form([
|
||||
Textarea::make('admin_feedback')
|
||||
->label('Revizyon Gerekçesi / Stajyere Not')
|
||||
->required()
|
||||
->placeholder('Örn: Başlığı ve içerikteki kod bloklarını düzenleyiniz.'),
|
||||
])
|
||||
->action(function ($record, array $data) {
|
||||
$record->status = 'rejected';
|
||||
$record->admin_feedback = $data['admin_feedback'];
|
||||
$record->save();
|
||||
|
||||
Notification::make()
|
||||
->title('Revizyon Talebi Gönderildi')
|
||||
->body('Stajyere revizyon bildirimi iletildi.')
|
||||
->warning()
|
||||
->send();
|
||||
}),
|
||||
|
||||
EditAction::make()
|
||||
->label(__('blog.edit')),
|
||||
])
|
||||
|
||||
Reference in New Issue
Block a user