diff --git a/app/Filament/Resources/StaticPages/Pages/EditStaticPage.php b/app/Filament/Resources/StaticPages/Pages/EditStaticPage.php index ad0b0d0..e187f31 100644 --- a/app/Filament/Resources/StaticPages/Pages/EditStaticPage.php +++ b/app/Filament/Resources/StaticPages/Pages/EditStaticPage.php @@ -3,7 +3,6 @@ namespace App\Filament\Resources\StaticPages\Pages; use App\Filament\Resources\StaticPages\StaticPageResource; -use Filament\Actions\DeleteAction; use Filament\Resources\Pages\EditRecord; class EditStaticPage extends EditRecord @@ -12,8 +11,6 @@ class EditStaticPage extends EditRecord protected function getHeaderActions(): array { - return [ - DeleteAction::make(), - ]; + return []; } } diff --git a/app/Filament/Resources/StaticPages/Pages/ListStaticPages.php b/app/Filament/Resources/StaticPages/Pages/ListStaticPages.php index f88ba78..6fc2d43 100644 --- a/app/Filament/Resources/StaticPages/Pages/ListStaticPages.php +++ b/app/Filament/Resources/StaticPages/Pages/ListStaticPages.php @@ -3,7 +3,6 @@ namespace App\Filament\Resources\StaticPages\Pages; use App\Filament\Resources\StaticPages\StaticPageResource; -use Filament\Actions\CreateAction; use Filament\Resources\Pages\ListRecords; class ListStaticPages extends ListRecords @@ -12,8 +11,6 @@ class ListStaticPages extends ListRecords protected function getHeaderActions(): array { - return [ - CreateAction::make(), - ]; + return []; } } diff --git a/app/Filament/Resources/StaticPages/Schemas/StaticPageForm.php b/app/Filament/Resources/StaticPages/Schemas/StaticPageForm.php index 08be851..c7dee2d 100644 --- a/app/Filament/Resources/StaticPages/Schemas/StaticPageForm.php +++ b/app/Filament/Resources/StaticPages/Schemas/StaticPageForm.php @@ -16,17 +16,25 @@ public static function configure(Schema $schema): Schema return $schema ->components([ TextInput::make('slug') - ->required() - ->unique(ignoreRecord: true), + ->disabled() + ->dehydrated(false), Tabs::make('Translations') ->tabs([ Tab::make('Română')->schema([ TextInput::make('title_ro')->required(), - RichEditor::make('body_ro')->required(), + RichEditor::make('body_ro') + ->required() + ->fileAttachmentsDisk('public') + ->fileAttachmentsDirectory('static-pages') + ->helperText(__('admin.resources.static_pages.blocks_hint')), ]), Tab::make('English')->schema([ TextInput::make('title_en')->required(), - RichEditor::make('body_en')->required(), + RichEditor::make('body_en') + ->required() + ->fileAttachmentsDisk('public') + ->fileAttachmentsDirectory('static-pages') + ->helperText(__('admin.resources.static_pages.blocks_hint')), ]), ]) ->columnSpanFull(), diff --git a/app/Filament/Resources/StaticPages/StaticPageResource.php b/app/Filament/Resources/StaticPages/StaticPageResource.php index d6fcd72..8a160ad 100644 --- a/app/Filament/Resources/StaticPages/StaticPageResource.php +++ b/app/Filament/Resources/StaticPages/StaticPageResource.php @@ -3,7 +3,6 @@ namespace App\Filament\Resources\StaticPages; use App\Filament\Concerns\HasTranslatedLabels; -use App\Filament\Resources\StaticPages\Pages\CreateStaticPage; use App\Filament\Resources\StaticPages\Pages\EditStaticPage; use App\Filament\Resources\StaticPages\Pages\ListStaticPages; use App\Filament\Resources\StaticPages\Schemas\StaticPageForm; @@ -14,6 +13,7 @@ use Filament\Schemas\Schema; use Filament\Support\Icons\Heroicon; use Filament\Tables\Table; +use Illuminate\Database\Eloquent\Builder; use UnitEnum; class StaticPageResource extends Resource @@ -26,6 +26,11 @@ class StaticPageResource extends Resource protected static string|UnitEnum|null $navigationGroup = 'Content'; + public static function getEloquentQuery(): Builder + { + return parent::getEloquentQuery()->whereIn('slug', StaticPage::MANAGED_SLUGS); + } + public static function form(Schema $schema): Schema { return StaticPageForm::configure($schema); @@ -47,7 +52,6 @@ public static function getPages(): array { return [ 'index' => ListStaticPages::route('/'), - 'create' => CreateStaticPage::route('/create'), 'edit' => EditStaticPage::route('/{record}/edit'), ]; } diff --git a/app/Filament/Resources/StaticPages/Tables/StaticPagesTable.php b/app/Filament/Resources/StaticPages/Tables/StaticPagesTable.php index 1b52119..8feb3ca 100644 --- a/app/Filament/Resources/StaticPages/Tables/StaticPagesTable.php +++ b/app/Filament/Resources/StaticPages/Tables/StaticPagesTable.php @@ -2,8 +2,6 @@ namespace App\Filament\Resources\StaticPages\Tables; -use Filament\Actions\BulkActionGroup; -use Filament\Actions\DeleteBulkAction; use Filament\Actions\EditAction; use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\TextColumn; @@ -37,11 +35,6 @@ public static function configure(Table $table): Table ]) ->recordActions([ EditAction::make(), - ]) - ->toolbarActions([ - BulkActionGroup::make([ - DeleteBulkAction::make(), - ]), ]); } } diff --git a/app/Models/StaticPage.php b/app/Models/StaticPage.php index 369e28e..b24a485 100644 --- a/app/Models/StaticPage.php +++ b/app/Models/StaticPage.php @@ -19,8 +19,22 @@ ])] class StaticPage extends Model { + /** + * Pages an administrator may edit. New pages cannot be added. + * + * @var list + */ + public const MANAGED_SLUGS = [ + 'terms', + 'privacy', + 'home', + 'about', + 'contact', + ]; + /** @use HasFactory */ use HasFactory; + use HasTranslations; protected function casts(): array @@ -31,7 +45,7 @@ protected function casts(): array } /** - * @param Builder $query + * @param Builder $query * @return Builder */ public function scopePublished(Builder $query): Builder diff --git a/database/migrations/2026_10_07_074937_restrict_static_pages_to_managed_set.php b/database/migrations/2026_10_07_074937_restrict_static_pages_to_managed_set.php new file mode 100644 index 0000000..59e5f7b --- /dev/null +++ b/database/migrations/2026_10_07_074937_restrict_static_pages_to_managed_set.php @@ -0,0 +1,28 @@ +run(); + + DB::table('static_pages') + ->whereNotIn('slug', ['terms', 'privacy', 'home', 'about', 'contact']) + ->delete(); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // + } +}; diff --git a/database/seeders/StaticPageSeeder.php b/database/seeders/StaticPageSeeder.php index bfdecdd..82a7482 100644 --- a/database/seeders/StaticPageSeeder.php +++ b/database/seeders/StaticPageSeeder.php @@ -13,6 +13,27 @@ class StaticPageSeeder extends Seeder public function run(): void { $pages = [ + [ + 'slug' => 'home', + 'title_ro' => __('home.hero_title', [], 'ro'), + 'title_en' => __('home.hero_title', [], 'en'), + 'body_ro' => __('home.hero_subtitle', [], 'ro'), + 'body_en' => __('home.hero_subtitle', [], 'en'), + ], + [ + 'slug' => 'about', + 'title_ro' => __('about.title', [], 'ro'), + 'title_en' => __('about.title', [], 'en'), + 'body_ro' => __('about.mission_body', [], 'ro'), + 'body_en' => __('about.mission_body', [], 'en'), + ], + [ + 'slug' => 'contact', + 'title_ro' => __('contact.title', [], 'ro'), + 'title_en' => __('contact.title', [], 'en'), + 'body_ro' => __('contact.subtitle', [], 'ro'), + 'body_en' => __('contact.subtitle', [], 'en'), + ], [ 'slug' => 'terms', 'title_ro' => 'Termeni și condiții', @@ -27,13 +48,6 @@ public function run(): void 'body_ro' => 'Protejăm datele personale conform legislației aplicabile și colectăm numai informațiile necesare funcționării platformei. Nu trebuie încărcate date cu caracter personal despre victime sau copii aflați în situații de risc. Pentru solicitări privind datele personale, contactați administratorul platformei.', 'body_en' => 'We protect personal data under applicable law and collect only information needed to operate the platform. Personally identifiable information about victims or children at risk must not be uploaded. Contact the platform administrator for privacy requests.', ], - [ - 'slug' => 'accessibility', - 'title_ro' => 'Declarație de accesibilitate', - 'title_en' => 'Accessibility Statement', - 'body_ro' => 'Ne propunem ca platforma să fie utilizabilă de cât mai multe persoane, inclusiv de utilizatorii tehnologiilor asistive. Lucrăm continuu la navigarea cu tastatura, contrast, structură semantică și alternative text. Ne puteți semnala orice barieră de accesibilitate.', - 'body_en' => 'We aim to make the platform usable by as many people as possible, including assistive-technology users. We continuously improve keyboard navigation, contrast, semantic structure, and text alternatives. Please report any accessibility barrier you encounter.', - ], ]; foreach ($pages as $page) { diff --git a/lang/en/admin.php b/lang/en/admin.php index e2d170f..92baa06 100644 --- a/lang/en/admin.php +++ b/lang/en/admin.php @@ -62,6 +62,7 @@ 'navigation' => 'Static Pages', 'label' => 'Static Page', 'plural' => 'Static Pages', + 'blocks_hint' => 'You can edit the text and images in the existing content. Maximum image size: 5 MB.', ], 'statistic_datasets' => [ 'navigation' => 'Statistic Datasets', diff --git a/lang/ro/admin.php b/lang/ro/admin.php index f4e773a..4502bbe 100644 --- a/lang/ro/admin.php +++ b/lang/ro/admin.php @@ -62,6 +62,7 @@ 'navigation' => 'Pagini statice', 'label' => 'Pagină statică', 'plural' => 'Pagini statice', + 'blocks_hint' => 'Poți edita textul și imaginile din conținutul existent. Dimensiunea maximă a unei imagini: 5 MB.', ], 'statistic_datasets' => [ 'navigation' => 'Seturi statistice', diff --git "a/resources/views/pages/\342\232\241about.blade.php" "b/resources/views/pages/\342\232\241about.blade.php" index fa445c1..e217c53 100644 --- "a/resources/views/pages/\342\232\241about.blade.php" +++ "b/resources/views/pages/\342\232\241about.blade.php" @@ -1,19 +1,26 @@ published()->where('slug', 'about')->first(); + } +}; ?>
- +

{{ __('about.mission_title') }}

-

{{ __('about.mission_body') }}

+
{!! $this->pageCopy()?->body ?: e(__('about.mission_body')) !!}
diff --git "a/resources/views/pages/\342\232\241contact.blade.php" "b/resources/views/pages/\342\232\241contact.blade.php" index 589ad85..c06e010 100644 --- "a/resources/views/pages/\342\232\241contact.blade.php" +++ "b/resources/views/pages/\342\232\241contact.blade.php" @@ -1,5 +1,6 @@ */ + public function pageCopy(): ?StaticPage + { + return StaticPage::query()->published()->where('slug', 'contact')->first(); + } + public function organizationKeys(): array { return ['anitp', 'fonpc', 'eliberare', 'tdh', 'world_vision', 'code']; @@ -17,7 +23,10 @@ public function organizationKeys(): array ?>
- +
@foreach ($this->organizationKeys() as $key) diff --git "a/resources/views/pages/\342\232\241home.blade.php" "b/resources/views/pages/\342\232\241home.blade.php" index e4346c5..b99b2fb 100644 --- "a/resources/views/pages/\342\232\241home.blade.php" +++ "b/resources/views/pages/\342\232\241home.blade.php" @@ -1,6 +1,7 @@ published()->where('slug', 'home')->first(); + } + /** @return Collection */ public function featuredResources(): Collection { @@ -36,9 +42,9 @@ public function featuredResources(): Collection -

{{ __('home.hero_title') }}

+

{{ $this->pageCopy()?->title ?: __('home.hero_title') }}

-

{{ __('home.hero_subtitle') }}

+
{!! $this->pageCopy()?->body ?: e(__('home.hero_subtitle')) !!}
{{ __('home.explore') }} {{ __('home.learn_more') }} diff --git a/tests/Feature/StaticPagesAdminTest.php b/tests/Feature/StaticPagesAdminTest.php new file mode 100644 index 0000000..096c1d4 --- /dev/null +++ b/tests/Feature/StaticPagesAdminTest.php @@ -0,0 +1,27 @@ +actingAs(User::factory()->admin()->create()); + + expect(StaticPage::query()->pluck('slug')->sort()->values()->all()) + ->toBe(['about', 'contact', 'home', 'privacy', 'terms']); + + Livewire::test(ListStaticPages::class) + ->assertSee('terms') + ->assertSee('privacy') + ->assertSee('home') + ->assertSee('about') + ->assertSee('contact') + ->assertDontSee('accessibility') + ->assertDontSee('Create'); + + Livewire::test(EditStaticPage::class, ['record' => 'about']) + ->assertSee('You can edit the text and images in the existing content. Maximum image size: 5 MB.', false) + ->assertSee('wire:name="App\\Filament\\Resources\\StaticPages\\Pages\\EditStaticPage"', false); +});