feat: add ApiResponse trait for standardized API responses

chore: update composer dependencies to include phppresentation

chore: update composer.lock after adding phppresentation

feat: create categories migration for category management

feat: create templates migration for template storage

feat: create template generations migration for tracking template usage

feat: create template keys migration for template customization

feat: create notifications migration for user notifications

feat: update API routes for categories, templates, and user profile management

docs: update API documentation to include new endpoints for profile and wallet
This commit is contained in:
2026-07-07 01:03:12 +03:30
parent cf0e6f82fd
commit ae974c2afa
68 changed files with 3594 additions and 100 deletions

View File

@@ -0,0 +1,54 @@
<?php
namespace App\Filament\Resources\Categories;
use App\Filament\Resources\Categories\Pages\CreateCategory;
use App\Filament\Resources\Categories\Pages\EditCategory;
use App\Filament\Resources\Categories\Pages\ListCategories;
use App\Filament\Resources\Categories\Schemas\CategoryForm;
use App\Filament\Resources\Categories\Tables\CategoriesTable;
use App\Models\Category;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use UnitEnum;
class CategoryResource extends Resource
{
protected static ?string $model = Category::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack;
protected static string|UnitEnum|null $navigationGroup = 'پاورپوینت‌ها';
protected static ?string $recordTitleAttribute = 'name';
protected static ?string $modelLabel = 'دسته‌بندی';
protected static ?string $pluralModelLabel = 'دسته‌بندی‌ها';
protected static ?string $navigationLabel = 'دسته‌بندی‌ها';
protected static ?int $navigationSort = 20;
public static function form(Schema $schema): Schema
{
return CategoryForm::configure($schema);
}
public static function table(Table $table): Table
{
return CategoriesTable::configure($table);
}
public static function getPages(): array
{
return [
'index' => ListCategories::route('/'),
'create' => CreateCategory::route('/create'),
'edit' => EditCategory::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\Categories\Pages;
use App\Filament\Resources\Categories\CategoryResource;
use Filament\Resources\Pages\CreateRecord;
class CreateCategory extends CreateRecord
{
protected static string $resource = CategoryResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Categories\Pages;
use App\Filament\Resources\Categories\CategoryResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditCategory extends EditRecord
{
protected static string $resource = CategoryResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Categories\Pages;
use App\Filament\Resources\Categories\CategoryResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListCategories extends ListRecords
{
protected static string $resource = CategoryResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace App\Filament\Resources\Categories\Schemas;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Schema;
class CategoryForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('name')
->label('نام')
->required()
->maxLength(255),
TextInput::make('slug')
->label('شناسه')
->required()
->unique(ignoreRecord: true)
->maxLength(255),
Textarea::make('description')
->label('توضیحات')
->maxLength(1000)
->rows(3),
Toggle::make('is_active')
->label('فعال')
->default(true),
]);
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace App\Filament\Resources\Categories\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\TernaryFilter;
use Filament\Tables\Table;
class CategoriesTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->label('نام')
->searchable()
->sortable(),
TextColumn::make('slug')
->label('شناسه')
->searchable()
->sortable(),
TextColumn::make('templates_count')
->label('تعداد قالب‌ها')
->counts('templates'),
IconColumn::make('is_active')
->label('فعال')
->boolean(),
TextColumn::make('created_at')
->label('تاریخ ایجاد')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
TernaryFilter::make('is_active')
->label('وضعیت')
->placeholder('همه')
->trueLabel('فعال')
->falseLabel('غیرفعال'),
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace App\Filament\Resources\Notifications;
use App\Filament\Resources\Notifications\Pages\CreateNotification;
use App\Filament\Resources\Notifications\Pages\EditNotification;
use App\Filament\Resources\Notifications\Pages\ListNotifications;
use App\Filament\Resources\Notifications\Pages\ViewNotification;
use App\Filament\Resources\Notifications\Schemas\NotificationForm;
use App\Filament\Resources\Notifications\Tables\NotificationsTable;
use App\Models\Notification;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use UnitEnum;
class NotificationResource extends Resource
{
protected static ?string $model = Notification::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedBell;
protected static string|UnitEnum|null $navigationGroup = 'اعلان‌ها';
protected static ?string $recordTitleAttribute = 'title';
protected static ?string $modelLabel = 'نوتیفیکیشن';
protected static ?string $pluralModelLabel = 'نوتیفیکیشن‌ها';
protected static ?string $navigationLabel = 'نوتیفیکیشن‌ها';
protected static ?int $navigationSort = 30;
public static function form(Schema $schema): Schema
{
return NotificationForm::configure($schema);
}
public static function table(Table $table): Table
{
return NotificationsTable::configure($table);
}
public static function getPages(): array
{
return [
'index' => ListNotifications::route('/'),
'create' => CreateNotification::route('/create'),
'view' => ViewNotification::route('/{record}'),
'edit' => EditNotification::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\Notifications\Pages;
use App\Filament\Resources\Notifications\NotificationResource;
use Filament\Resources\Pages\CreateRecord;
class CreateNotification extends CreateRecord
{
protected static string $resource = NotificationResource::class;
}

View File

@@ -0,0 +1,21 @@
<?php
namespace App\Filament\Resources\Notifications\Pages;
use App\Filament\Resources\Notifications\NotificationResource;
use Filament\Actions\DeleteAction;
use Filament\Actions\ViewAction;
use Filament\Resources\Pages\EditRecord;
class EditNotification extends EditRecord
{
protected static string $resource = NotificationResource::class;
protected function getHeaderActions(): array
{
return [
ViewAction::make(),
DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Notifications\Pages;
use App\Filament\Resources\Notifications\NotificationResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListNotifications extends ListRecords
{
protected static string $resource = NotificationResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Notifications\Pages;
use App\Filament\Resources\Notifications\NotificationResource;
use Filament\Actions\EditAction;
use Filament\Resources\Pages\ViewRecord;
class ViewNotification extends ViewRecord
{
protected static string $resource = NotificationResource::class;
protected function getHeaderActions(): array
{
return [
EditAction::make(),
];
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Filament\Resources\Notifications\Schemas;
use App\Enums\NotificationType;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;
class NotificationForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
Select::make('user_id')
->label('کاربر')
->relationship('user', 'name')
->searchable()
->required(),
Select::make('type')
->label('نوع')
->options(collect(NotificationType::cases())->mapWithKeys(fn (NotificationType $type) => [$type->value => $type->label()]))
->required(),
TextInput::make('title')
->label('عنوان')
->required()
->maxLength(255),
Textarea::make('body')
->label('متن')
->required()
->rows(4),
]);
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace App\Filament\Resources\Notifications\Tables;
use App\Enums\NotificationType;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Actions\ViewAction;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Filters\TernaryFilter;
use Filament\Tables\Table;
class NotificationsTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('user.name')
->label('کاربر')
->searchable()
->sortable(),
TextColumn::make('type')
->label('نوع')
->badge()
->formatStateUsing(fn (NotificationType $state): string => $state->label()),
TextColumn::make('title')
->label('عنوان')
->searchable()
->limit(40),
IconColumn::make('read_at')
->label('خوانده شده')
->boolean()
->getStateUsing(fn ($record): bool => $record->read_at !== null),
TextColumn::make('created_at')
->label('تاریخ ایجاد')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->defaultSort('created_at', 'desc')
->filters([
SelectFilter::make('type')
->label('نوع')
->options(collect(NotificationType::cases())->mapWithKeys(fn (NotificationType $type) => [$type->value => $type->label()])),
TernaryFilter::make('read_at')
->label('وضعیت')
->placeholder('همه')
->trueLabel('خوانده شده')
->falseLabel('خوانده نشده')
->queries(
true: fn ($query) => $query->whereNotNull('read_at'),
false: fn ($query) => $query->whereNull('read_at'),
),
])
->recordActions([
ViewAction::make(),
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\TemplateGenerations\Pages;
use App\Filament\Resources\TemplateGenerations\TemplateGenerationResource;
use Filament\Resources\Pages\ListRecords;
class ListTemplateGenerations extends ListRecords
{
protected static string $resource = TemplateGenerationResource::class;
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\TemplateGenerations\Pages;
use App\Filament\Resources\TemplateGenerations\TemplateGenerationResource;
use Filament\Resources\Pages\ViewRecord;
class ViewTemplateGeneration extends ViewRecord
{
protected static string $resource = TemplateGenerationResource::class;
}

View File

@@ -0,0 +1,63 @@
<?php
namespace App\Filament\Resources\TemplateGenerations\Tables;
use App\Enums\TemplateGenerationStatus;
use Filament\Actions\ViewAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
class TemplateGenerationsTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('uuid')
->label('شناسه')
->searchable()
->copyable(),
TextColumn::make('template.title')
->label('قالب')
->searchable()
->sortable(),
TextColumn::make('status')
->label('وضعیت')
->badge()
->formatStateUsing(fn (TemplateGenerationStatus $state): string => $state->label())
->color(fn (TemplateGenerationStatus $state): string => match ($state) {
TemplateGenerationStatus::Pending => 'gray',
TemplateGenerationStatus::Processing => 'warning',
TemplateGenerationStatus::Completed => 'success',
TemplateGenerationStatus::Failed => 'danger',
}),
TextColumn::make('requester.name')
->label('درخواست‌دهنده')
->searchable()
->placeholder('—'),
TextColumn::make('error_message')
->label('خطا')
->limit(50)
->placeholder('—'),
TextColumn::make('created_at')
->label('تاریخ')
->dateTime()
->sortable(),
])
->defaultSort('created_at', 'desc')
->filters([
SelectFilter::make('status')
->label('وضعیت')
->options([
TemplateGenerationStatus::Pending->value => TemplateGenerationStatus::Pending->label(),
TemplateGenerationStatus::Processing->value => TemplateGenerationStatus::Processing->label(),
TemplateGenerationStatus::Completed->value => TemplateGenerationStatus::Completed->label(),
TemplateGenerationStatus::Failed->value => TemplateGenerationStatus::Failed->label(),
]),
])
->recordActions([
ViewAction::make(),
]);
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace App\Filament\Resources\TemplateGenerations;
use App\Filament\Resources\TemplateGenerations\Pages\ListTemplateGenerations;
use App\Filament\Resources\TemplateGenerations\Pages\ViewTemplateGeneration;
use App\Filament\Resources\TemplateGenerations\Tables\TemplateGenerationsTable;
use App\Models\TemplateGeneration;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use UnitEnum;
class TemplateGenerationResource extends Resource
{
protected static ?string $model = TemplateGeneration::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedDocumentArrowDown;
protected static string|UnitEnum|null $navigationGroup = 'پاورپوینت‌ها';
protected static ?string $recordTitleAttribute = 'uuid';
protected static ?string $modelLabel = 'تولید';
protected static ?string $pluralModelLabel = 'تولیدها';
protected static ?string $navigationLabel = 'تولیدها';
protected static ?int $navigationSort = 22;
public static function table(Table $table): Table
{
return TemplateGenerationsTable::configure($table);
}
public static function getPages(): array
{
return [
'index' => ListTemplateGenerations::route('/'),
'view' => ViewTemplateGeneration::route('/{record}'),
];
}
public static function canCreate(): bool
{
return false;
}
public static function canEdit($record): bool
{
return false;
}
public static function canDelete($record): bool
{
return false;
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\Templates\Pages;
use App\Filament\Resources\Templates\TemplateResource;
use Filament\Resources\Pages\CreateRecord;
class CreateTemplate extends CreateRecord
{
protected static string $resource = TemplateResource::class;
/**
* @param array<string, mixed> $data
* @return array<string, mixed>
*/
protected function mutateFormDataBeforeCreate(array $data): array
{
$data['created_by'] = auth()->id();
return $data;
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace App\Filament\Resources\Templates\Pages;
use App\Filament\Resources\Templates\TemplateResource;
use Filament\Actions\DeleteAction;
use Filament\Actions\ViewAction;
use Filament\Resources\Pages\EditRecord;
class EditTemplate extends EditRecord
{
protected static string $resource = TemplateResource::class;
protected function getHeaderActions(): array
{
return [
ViewAction::make(),
DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Templates\Pages;
use App\Filament\Resources\Templates\TemplateResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListTemplates extends ListRecords
{
protected static string $resource = TemplateResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Templates\Pages;
use App\Filament\Resources\Templates\TemplateResource;
use Filament\Actions\EditAction;
use Filament\Resources\Pages\ViewRecord;
class ViewTemplate extends ViewRecord
{
protected static string $resource = TemplateResource::class;
protected function getHeaderActions(): array
{
return [
EditAction::make(),
];
}
}

View File

@@ -0,0 +1,66 @@
<?php
namespace App\Filament\Resources\Templates\RelationManagers;
use App\Enums\TemplateGenerationStatus;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
class GenerationsRelationManager extends RelationManager
{
protected static string $relationship = 'generations';
protected static ?string $title = 'تولیدها';
protected static ?string $modelLabel = 'تولید';
protected static ?string $pluralModelLabel = 'تولیدها';
public function table(Table $table): Table
{
return $table
->recordTitleAttribute('uuid')
->columns([
TextColumn::make('uuid')
->label('شناسه')
->searchable()
->copyable(),
TextColumn::make('status')
->label('وضعیت')
->badge()
->formatStateUsing(fn (TemplateGenerationStatus $state): string => $state->label())
->color(fn (TemplateGenerationStatus $state): string => match ($state) {
TemplateGenerationStatus::Pending => 'gray',
TemplateGenerationStatus::Processing => 'warning',
TemplateGenerationStatus::Completed => 'success',
TemplateGenerationStatus::Failed => 'danger',
}),
TextColumn::make('requester.name')
->label('درخواست‌دهنده')
->placeholder('—'),
TextColumn::make('error_message')
->label('خطا')
->limit(40)
->placeholder('—'),
TextColumn::make('created_at')
->label('تاریخ')
->dateTime()
->sortable(),
])
->defaultSort('created_at', 'desc')
->filters([
SelectFilter::make('status')
->label('وضعیت')
->options([
TemplateGenerationStatus::Pending->value => TemplateGenerationStatus::Pending->label(),
TemplateGenerationStatus::Processing->value => TemplateGenerationStatus::Processing->label(),
TemplateGenerationStatus::Completed->value => TemplateGenerationStatus::Completed->label(),
TemplateGenerationStatus::Failed->value => TemplateGenerationStatus::Failed->label(),
]),
])
->recordActions([])
->toolbarActions([]);
}
}

View File

@@ -0,0 +1,106 @@
<?php
namespace App\Filament\Resources\Templates\RelationManagers;
use App\Enums\TemplateKeyType;
use Filament\Actions\CreateAction;
use Filament\Actions\DeleteAction;
use Filament\Actions\EditAction;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Schemas\Components\Utilities\Get;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class KeysRelationManager extends RelationManager
{
protected static string $relationship = 'keys';
protected static ?string $title = 'کلیدها';
protected static ?string $modelLabel = 'کلید';
protected static ?string $pluralModelLabel = 'کلیدها';
public function form(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('key')
->label('کلید')
->helperText('در فایل پاورپوینت برای متن به‌صورت {{key}} و برای عکس/چارت به‌صورت نام شکل (shape name) استفاده می‌شود.')
->required()
->maxLength(255),
TextInput::make('label')
->label('برچسب')
->required()
->maxLength(255),
Select::make('type')
->label('نوع')
->options([
TemplateKeyType::Text->value => TemplateKeyType::Text->label(),
TemplateKeyType::Image->value => TemplateKeyType::Image->label(),
TemplateKeyType::Chart->value => TemplateKeyType::Chart->label(),
])
->required()
->live(),
TextInput::make('shape_name')
->label('نام شکل (Shape Name)')
->helperText('نام شکل تعیین‌شده در Selection Pane نرم‌افزار PowerPoint')
->visible(fn (Get $get): bool => $get('type') !== TemplateKeyType::Text->value)
->maxLength(255),
TextInput::make('description')
->label('راهنما')
->helperText('توضیحی که برای مصرف‌کننده API نمایش داده می‌شود')
->maxLength(255),
Toggle::make('is_required')
->label('اجباری')
->default(true),
TextInput::make('sort_order')
->label('ترتیب نمایش')
->numeric()
->integer()
->default(0),
]);
}
public function table(Table $table): Table
{
return $table
->recordTitleAttribute('key')
->columns([
TextColumn::make('key')
->label('کلید')
->searchable()
->sortable(),
TextColumn::make('label')
->label('برچسب')
->searchable(),
TextColumn::make('type')
->label('نوع')
->badge()
->formatStateUsing(fn (TemplateKeyType $state): string => $state->label()),
TextColumn::make('shape_name')
->label('نام شکل')
->placeholder('—'),
IconColumn::make('is_required')
->label('اجباری')
->boolean(),
TextColumn::make('sort_order')
->label('ترتیب')
->sortable(),
])
->defaultSort('sort_order')
->headerActions([
CreateAction::make(),
])
->recordActions([
EditAction::make(),
DeleteAction::make(),
]);
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace App\Filament\Resources\Templates\Schemas;
use App\Models\Category;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Schema;
class TemplateForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
Select::make('category_id')
->label('دسته‌بندی')
->options(fn (): array => Category::query()->pluck('name', 'id')->all())
->searchable()
->required(),
TextInput::make('title')
->label('عنوان')
->required()
->maxLength(255),
TextInput::make('slug')
->label('شناسه')
->required()
->unique(ignoreRecord: true)
->maxLength(255),
Textarea::make('description')
->label('توضیحات')
->maxLength(1000)
->rows(3),
FileUpload::make('file_path')
->label('فایل پاورپوینت')
->disk('local')
->directory('templates/sources')
->acceptedFileTypes(['application/vnd.openxmlformats-officedocument.presentationml.presentation'])
->required()
->visibility('private'),
FileUpload::make('thumbnail_path')
->label('تصویر بندانگشتی')
->disk('public')
->directory('templates/thumbnails')
->image(),
Toggle::make('is_active')
->label('فعال')
->default(true),
]);
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace App\Filament\Resources\Templates\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Actions\ViewAction;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Filters\TernaryFilter;
use Filament\Tables\Table;
class TemplatesTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('title')
->label('عنوان')
->searchable()
->sortable(),
TextColumn::make('category.name')
->label('دسته‌بندی')
->searchable()
->sortable(),
TextColumn::make('keys_count')
->label('تعداد کلیدها')
->counts('keys'),
IconColumn::make('is_active')
->label('فعال')
->boolean(),
TextColumn::make('created_at')
->label('تاریخ ایجاد')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
SelectFilter::make('category_id')
->label('دسته‌بندی')
->relationship('category', 'name'),
TernaryFilter::make('is_active')
->label('وضعیت')
->placeholder('همه')
->trueLabel('فعال')
->falseLabel('غیرفعال'),
])
->recordActions([
ViewAction::make(),
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}

View File

@@ -0,0 +1,66 @@
<?php
namespace App\Filament\Resources\Templates;
use App\Filament\Resources\Templates\Pages\CreateTemplate;
use App\Filament\Resources\Templates\Pages\EditTemplate;
use App\Filament\Resources\Templates\Pages\ListTemplates;
use App\Filament\Resources\Templates\Pages\ViewTemplate;
use App\Filament\Resources\Templates\RelationManagers\GenerationsRelationManager;
use App\Filament\Resources\Templates\RelationManagers\KeysRelationManager;
use App\Filament\Resources\Templates\Schemas\TemplateForm;
use App\Filament\Resources\Templates\Tables\TemplatesTable;
use App\Models\Template;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use UnitEnum;
class TemplateResource extends Resource
{
protected static ?string $model = Template::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedPresentationChartBar;
protected static string|UnitEnum|null $navigationGroup = 'پاورپوینت‌ها';
protected static ?string $recordTitleAttribute = 'title';
protected static ?string $modelLabel = 'قالب';
protected static ?string $pluralModelLabel = 'قالب‌ها';
protected static ?string $navigationLabel = 'قالب‌ها';
protected static ?int $navigationSort = 21;
public static function form(Schema $schema): Schema
{
return TemplateForm::configure($schema);
}
public static function table(Table $table): Table
{
return TemplatesTable::configure($table);
}
public static function getRelations(): array
{
return [
KeysRelationManager::class,
GenerationsRelationManager::class,
];
}
public static function getPages(): array
{
return [
'index' => ListTemplates::route('/'),
'create' => CreateTemplate::route('/create'),
'view' => ViewTemplate::route('/{record}'),
'edit' => EditTemplate::route('/{record}/edit'),
];
}
}