Version 1.0.0

This commit is contained in:
2025-05-10 16:52:45 +02:00
commit bed95bff35
459 changed files with 36475 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
<?php
namespace App\Filament\Pages;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Pages\Page;
use Filament\Actions\Action;
use Filament\Notifications\Notification;
use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Builder;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Components\Card;
use Filament\Support\Enums\MaxWidth;
use Filament\Forms\Components\RichEditor;
class Contact extends Page implements HasForms
{
use InteractsWithForms;
public static function canAccess(): bool
{
return auth()->user()->can('manage_contact') || auth()->user()->can('admin');
}
protected static ?string $navigationIcon = 'heroicon-o-adjustments-horizontal';
protected static ?string $navigationGroup = 'Ustawienia';
protected static ?string $title = 'Kontakt';
protected static ?int $navigationSort = 3;
protected static string $view = 'filament.pages.custom-edit-page';
public function getMaxContentWidth(): MaxWidth
{
return MaxWidth::FourExtraLarge;
}
public ?array $data = [];
public function mount(): void
{
$firstRecord = \App\Models\Contact::first();
if ($firstRecord) {
$this->data = $firstRecord->toArray();
$this->form->fill($this->data);
}
}
public function form(Form $form): Form
{
return $form->schema([
Card::make()
->schema([
RichEditor::make('address')
->label('Adres')
->required()
->columnSpanFull(),
TextInput::make('telephone')
->label('Telefon')
->required()
->maxLength(2048),
TextInput::make('email')
->label('E-mail')
->required()
->maxLength(2048),
TextInput::make('fax')
->label('Faks')
->required()
->maxLength(2048),
]),
Card::make()
->schema([
TextInput::make('system_email')
->label('Na ten adres będzie wysyłany e-mail z formularza kontaktowego')
->required()
->maxLength(2048),
]),
])->statePath('data');
}
public function getFormActions(): array
{
return [
Action::make('save')
->label('Zapisz')
->action('save'),
];
}
public function save(): void
{
$validatedData = $this->form->getState();
try {
$contact = \App\Models\Contact::first();
$contact->fill($validatedData);
$contact->save();
Notification::make()
->title('Sukces!')
->body('Rekord został zapisany pomyślnie.')
->success()
->send();
} catch (\Exception $e) {
Notification::make()
->title('Błąd!')
->body('Wystąpił problem podczas zapisywania rekordu: ' . $e->getMessage())
->danger()
->send();
}
}
}

View File

@@ -0,0 +1,124 @@
<?php
namespace App\Filament\Pages;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Pages\Page;
use Filament\Actions\Action;
use Filament\Notifications\Notification;
use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Builder;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Components\Card;
use Filament\Support\Enums\MaxWidth;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\FileUpload;
use Composer\InstalledVersions;
use Symfony\Component\Process\Process;
class Diagnostic extends Page
{
public static function canAccess(): bool
{
return auth()->user()->can('view_diagnostics') || auth()->user()->can('admin');
}
protected static ?string $navigationIcon = 'heroicon-o-information-circle';
protected static ?string $navigationGroup = 'Ustawienia';
protected static ?string $title = 'Diagnostyka';
protected static ?int $navigationSort = 2;
protected static string $view = 'filament.pages.diagnostic-page';
public function getMaxContentWidth(): MaxWidth
{
return MaxWidth::FourExtraLarge;
}
public array $composerPackages = [];
public array $npmPackages = [];
public function mount(): void
{
$composerJson = json_decode(file_get_contents(base_path('composer.json')), true);
$direct = [];
foreach (['require', 'require-dev'] as $section) {
if (isset($composerJson[$section])) {
foreach ($composerJson[$section] as $name => $ver) {
if (strpos($name, 'ext-') !== 0 && $name !== 'php') {
$direct[] = $name;
}
}
}
}
foreach ($direct as $package) {
if (\Composer\InstalledVersions::isInstalled($package)) {
$this->composerPackages[$package] = [
'name' => $package,
'current_version' => \Composer\InstalledVersions::getPrettyVersion($package),
'latest_version' => null,
'is_up_to_date' => true,
];
}
}
try {
$env = $_ENV;
$env['HOME'] = base_path();
$composerProcess = new Process(['composer', 'outdated', '--format=json', '--direct'], base_path(), $env);
$composerProcess->run();
if ($composerProcess->isSuccessful()) {
$outdatedComposerPackages = json_decode($composerProcess->getOutput(), true);
foreach ($outdatedComposerPackages['installed'] ?? [] as $outdatedPackage) {
if (isset($this->composerPackages[$outdatedPackage['name']])) {
$this->composerPackages[$outdatedPackage['name']]['latest_version'] = $outdatedPackage['latest'];
$this->composerPackages[$outdatedPackage['name']]['is_up_to_date'] = false;
}
}
} else {
throw new \Exception($composerProcess->getErrorOutput());
}
} catch (\Exception $e) {
dd('Composer Error: ' . $e->getMessage());
}
try {
$packageJsonPath = base_path('package.json');
if (file_exists($packageJsonPath)) {
$packageJsonContent = json_decode(file_get_contents($packageJsonPath), true);
$outdatedNpmPackages = [];
$env = $_ENV;
$env['HOME'] = base_path();
$npmProcess = new Process(['npm', 'outdated', '--json'], base_path(), $env);
$npmProcess->run();
$outdatedNpmPackages = json_decode($npmProcess->getOutput(), true);
foreach (['dependencies', 'devDependencies'] as $dependencyType) {
if (isset($packageJsonContent[$dependencyType])) {
foreach ($packageJsonContent[$dependencyType] as $name => $version) {
$this->npmPackages[] = [
'name' => $name,
'current_version' => isset($outdatedNpmPackages[$name]) ? $outdatedNpmPackages[$name]['current'] : $version,
'wanted_version' => isset($outdatedNpmPackages[$name]) ? $outdatedNpmPackages[$name]['wanted'] : null,
'latest_version' => isset($outdatedNpmPackages[$name]) ? $outdatedNpmPackages[$name]['latest'] : null,
'is_up_to_date' => !isset($outdatedNpmPackages[$name]),
];
}
}
}
}
} catch (\Exception $e) {
dd('NPM Error: ' . $e->getMessage());
}
}
}

View File

@@ -0,0 +1,156 @@
<?php
namespace App\Filament\Pages;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Pages\Page;
use Filament\Actions\Action;
use Filament\Notifications\Notification;
use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Builder;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Components\Card;
use Filament\Forms\Components\Select;
use Filament\Support\Enums\MaxWidth;
class Footer extends Page implements HasForms
{
use InteractsWithForms;
public static function canAccess(): bool
{
return auth()->user()->can('manage_footer') || auth()->user()->can('admin');
}
protected static ?string $navigationIcon = 'heroicon-o-adjustments-horizontal';
protected static ?string $navigationGroup = 'Ustawienia';
protected static ?string $title = 'Stopka';
protected static ?int $navigationSort = 5;
protected static string $view = 'filament.pages.custom-edit-page';
public function getMaxContentWidth(): MaxWidth
{
return MaxWidth::FourExtraLarge;
}
public ?array $data = [];
public function mount(): void
{
$firstRecord = \App\Models\Footer::first();
if ($firstRecord) {
$this->data = $firstRecord->toArray();
$this->form->fill($this->data);
}
}
public function form(Form $form): Form
{
return $form->schema([
Card::make()
->schema([
Select::make('wosp_link')
->label('Powiązany artykuł WOŚP')
->options(function () {
return \App\Models\Article::all()->pluck('title', 'id');
})
->nullable()
->default(null)
->searchable()
->preload()
->reactive(),
]),
Card::make()
->schema([
Builder::make('links')
->label('Odnośniki')
->addActionLabel('Dodaj odnośnik')
->blocks([
Builder\Block::make('link')
->label(function (?array $state): string {
if ($state === null) {
return 'Odnośnik';
}
return $state['name'] ?? 'Odnośnik';
})
->schema([
TextInput::make('name')
->label('Nazwa')
->required(),
TextInput::make('url')
->label('Ścieżka lub URL')
->required(),
Toggle::make('external')
->label('Otwieraj w nowej karcie')
->required(),
])
->columns(2),
])
]),
Card::make()
->schema([
Builder::make('registration_hours')
->label('Godziny rejestracji')
->addActionLabel('Dodaj dzień z godzinami')
->blocks([
Builder\Block::make('registration_hour')
->label(function (?array $state): string {
if ($state === null) {
return 'Godziny rejestracji';
}
return $state['day'] ?? 'Godzina rejestracji';
})
->schema([
TextInput::make('day')
->label('Dzień tygodnia')
->required(),
TextInput::make('hours')
->label('Godziny')
->required(),
])
->columns(2),
])
])
])->statePath('data');
}
public function getFormActions(): array
{
return [
Action::make('save')
->label('Zapisz')
->action('save'),
];
}
public function save(): void
{
$validatedData = $this->form->getState();
try {
$footer = \App\Models\Footer::first();
$footer->fill($validatedData);
$footer->save();
Notification::make()
->title('Sukces!')
->body('Rekord został zapisany pomyślnie.')
->success()
->send();
} catch (\Exception $e) {
Notification::make()
->title('Błąd!')
->body('Wystąpił problem podczas zapisywania rekordu: ' . $e->getMessage())
->danger()
->send();
}
}
}

View File

@@ -0,0 +1,157 @@
<?php
namespace App\Filament\Pages;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Pages\Page;
use Filament\Actions\Action;
use Filament\Notifications\Notification;
use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Builder;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Components\Card;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\FileUpload;
use Filament\Support\Enums\MaxWidth;
class Header extends Page implements HasForms
{
use InteractsWithForms;
public static function canAccess(): bool
{
return auth()->user()->can('manage_header') || auth()->user()->can('admin');
}
protected static ?string $navigationIcon = 'heroicon-o-adjustments-horizontal';
protected static ?string $navigationGroup = 'Ustawienia';
protected static ?string $title = 'Nagłówek';
protected static ?int $navigationSort = 4;
protected static string $view = 'filament.pages.custom-edit-page';
public function getMaxContentWidth(): MaxWidth
{
return MaxWidth::FourExtraLarge;
}
public ?array $data = [];
public function mount(): void
{
$firstRecord = \App\Models\Header::first();
if ($firstRecord) {
$this->data = $firstRecord->toArray();
$this->form->fill($this->data);
}
}
public function form(Form $form): Form
{
return $form->schema([
Card::make()
->schema([
Grid::make(2)
->schema([
TextInput::make('title1')
->label('Tytuł 1')
->required()
->maxLength(2048),
TextInput::make('title2')
->label('Tytuł 2')
->required()
->maxLength(2048),
]),
TextInput::make('subtitle')
->label('Podtytuł')
->maxLength(2048),
FileUpload::make('logo')
->image()
->imageEditor()
->acceptedFileTypes(['image/png'])
->label('Logo strony')
->disk('public')
->directory('header-logo')
->default(null),
TextInput::make('telephone')
->label('Numer telefonu')
->required()
->maxLength(15),
]),
Card::make()
->schema([
Builder::make('links')
->label('Odnośniki')
->addActionLabel('Dodaj odnośnik')
->blocks([
Builder\Block::make('link')
->label(function (?array $state): string {
if ($state === null) {
return 'Odnośnik';
}
return $state['name'] ?? 'Odnośnik';
})
->schema([
TextInput::make('name')
->label('Nazwa')
->required(),
FileUpload::make('icon')
->image()
->imageEditor()
->label('Ikona')
->disk('public')
->directory('header-links')
->default(null),
TextInput::make('icon-alt')
->label('Opis ikony')
->default(null),
TextInput::make('url')
->label('Ścieżka lub URL')
->required(),
Toggle::make('external')
->label('Otwieraj w nowej karcie')
->required(),
])
->columns(1),
])
])
])->statePath('data');
}
public function getFormActions(): array
{
return [
Action::make('save')
->label('Zapisz')
->action('save'),
];
}
public function save(): void
{
$validatedData = $this->form->getState();
try {
$header = \App\Models\Header::first();
$header->fill($validatedData);
$header->save();
Notification::make()
->title('Sukces!')
->body('Rekord został zapisany pomyślnie.')
->success()
->send();
} catch (\Exception $e) {
Notification::make()
->title('Błąd!')
->body('Wystąpił problem podczas zapisywania rekordu: ' . $e->getMessage())
->danger()
->send();
}
}
}

View File

@@ -0,0 +1,151 @@
<?php
namespace App\Filament\Pages;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Pages\Page;
use Filament\Actions\Action;
use Filament\Notifications\Notification;
use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Builder;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Components\Card;
use Filament\Support\Enums\MaxWidth;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\FileUpload;
class Homepage extends Page implements HasForms
{
use InteractsWithForms;
public static function canAccess(): bool
{
return auth()->user()->can('manage_homepage') || auth()->user()->can('admin');
}
protected static ?string $navigationIcon = 'heroicon-o-home';
protected static ?string $navigationGroup = 'Treści';
protected static ?string $title = 'Strona główna';
protected static ?int $navigationSort = 3;
protected static string $view = 'filament.pages.custom-edit-page';
public function getMaxContentWidth(): MaxWidth
{
return MaxWidth::FourExtraLarge;
}
public ?array $data = [];
public function mount(): void
{
$firstRecord = \App\Models\Homepage::first();
if ($firstRecord) {
$this->data = $firstRecord->toArray();
$this->form->fill($this->data);
}
}
public function form(Form $form): Form
{
return $form->schema([
Card::make()
->schema([
TextInput::make('title')
->label('Tytuł strony')
->required()
->maxLength(2048),
FileUpload::make('photo')
->image()
->imageEditor()
->disk('public')
->directory('homepage')
->label('Zdjęcie'),
RichEditor::make('content')
->label('Treść strony')
->required()
->columnSpanFull(),
]),
Card::make()
->schema([
Builder::make('carousel_photos')
->label('Zdjęcia w karuzeli')
->addActionLabel('Dodaj zdjęcie')
->collapsible()
->collapsed()
->reorderable()
->blocks([
Builder\Block::make('carousel_photo')
->label(function (?array $state): string {
if ($state === null) {
return 'Zdjęcie';
}
return $state['name'] ?? 'Zdjęcie';
})
->schema([
TextInput::make('name')
->label('Nazwa')
->required(),
FileUpload::make('photo')
->image()
->imageEditor()
->required()
->label('Zdjęcie')
->disk('public')
->directory('homepage-carousel')
->default(null),
TextInput::make('description')
->label('Opis')
->default(null)
->required(),
TextInput::make('url')
->label('Ścieżka lub URL')
->required(),
Toggle::make('external')
->label('Otwieraj w nowej karcie')
->default(false)
->required(),
])
->columns(1),
])
])
])->statePath('data');
}
public function getFormActions(): array
{
return [
Action::make('save')
->label('Zapisz')
->action('save'),
];
}
public function save(): void
{
$validatedData = $this->form->getState();
try {
$homepage = \App\Models\Homepage::first();
$homepage->fill($validatedData);
$homepage->save();
Notification::make()
->title('Sukces!')
->body('Rekord został zapisany pomyślnie.')
->success()
->send();
} catch (\Exception $e) {
Notification::make()
->title('Błąd!')
->body('Wystąpił problem podczas zapisywania rekordu: ' . $e->getMessage())
->danger()
->send();
}
}
}

View File

@@ -0,0 +1,103 @@
<?php
namespace App\Filament\Pages;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Pages\Page;
use Filament\Actions\Action;
use Filament\Notifications\Notification;
use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Builder;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Components\Card;
use Filament\Support\Enums\MaxWidth;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\Select;
class Location extends Page implements HasForms
{
use InteractsWithForms;
public static function canAccess(): bool
{
return auth()->user()->can('manage_location') || auth()->user()->can('admin');
}
protected static ?string $navigationIcon = 'heroicon-o-map-pin';
protected static ?string $navigationGroup = 'Pozostałe';
protected static ?string $title = 'Mapa budynków';
protected static ?int $navigationSort = 2;
protected static string $view = 'filament.pages.custom-edit-page';
public function getMaxContentWidth(): MaxWidth
{
return MaxWidth::FourExtraLarge;
}
public ?array $data = [];
public function mount(): void
{
$firstRecord = \App\Models\Location::first();
if ($firstRecord) {
$this->data = $firstRecord->toArray();
$this->form->fill($this->data);
}
}
public function form(Form $form): Form
{
return $form->schema([
Card::make()
->schema([
Select::make('photo_id')
->label('Powiązane zdjęcie')
->options(function () {
return \App\Models\Photo::all()->pluck('image_name', 'id');
})
->nullable()
->default(null)
->searchable()
->preload()
->reactive(),
]),
])->statePath('data');
}
public function getFormActions(): array
{
return [
Action::make('save')
->label('Zapisz')
->action('save'),
];
}
public function save(): void
{
$validatedData = $this->form->getState();
try {
$location = \App\Models\Location::first();
$location->fill($validatedData);
$location->save();
Notification::make()
->title('Sukces!')
->body('Rekord został zapisany pomyślnie.')
->success()
->send();
} catch (\Exception $e) {
Notification::make()
->title('Błąd!')
->body('Wystąpił problem podczas zapisywania rekordu: ' . $e->getMessage())
->danger()
->send();
}
}
}

View File

@@ -0,0 +1,103 @@
<?php
namespace App\Filament\Pages;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Pages\Page;
use Filament\Actions\Action;
use Filament\Notifications\Notification;
use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Builder;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Components\Card;
use Filament\Support\Enums\MaxWidth;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\Select;
class Price extends Page implements HasForms
{
use InteractsWithForms;
public static function canAccess(): bool
{
return auth()->user()->can('manage_prices') || auth()->user()->can('admin');
}
protected static ?string $navigationIcon = 'heroicon-o-banknotes';
protected static ?string $navigationGroup = 'Pozostałe';
protected static ?string $title = 'Cennik badań';
protected static ?int $navigationSort = 1;
protected static string $view = 'filament.pages.custom-edit-page';
public function getMaxContentWidth(): MaxWidth
{
return MaxWidth::FourExtraLarge;
}
public ?array $data = [];
public function mount(): void
{
$firstRecord = \App\Models\Price::first();
if ($firstRecord) {
$this->data = $firstRecord->toArray();
$this->form->fill($this->data);
}
}
public function form(Form $form): Form
{
return $form->schema([
Card::make()
->schema([
Select::make('attachment_id')
->label('Powiązany załącznik')
->options(function () {
return \App\Models\Attachment::all()->pluck('file_name', 'id');
})
->nullable()
->default(null)
->searchable()
->preload()
->reactive(),
]),
])->statePath('data');
}
public function getFormActions(): array
{
return [
Action::make('save')
->label('Zapisz')
->action('save'),
];
}
public function save(): void
{
$validatedData = $this->form->getState();
try {
$price = \App\Models\Price::first();
$price->fill($validatedData);
$price->save();
Notification::make()
->title('Sukces!')
->body('Rekord został zapisany pomyślnie.')
->success()
->send();
} catch (\Exception $e) {
Notification::make()
->title('Błąd!')
->body('Wystąpił problem podczas zapisywania rekordu: ' . $e->getMessage())
->danger()
->send();
}
}
}

View File

@@ -0,0 +1,175 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\ArticleNewsResource\Pages;
use App\Filament\Resources\ArticleNewsResource\RelationManagers;
use App\Models\ArticleNews;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\Card;
use Filament\Forms\Set;
use Illuminate\Support\Str;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Select;
class ArticleNewsResource extends Resource
{
public static function canAccess(): bool
{
return auth()->user()->can('manage_news') || auth()->user()->can('admin');
}
protected static ?string $model = ArticleNews::class;
protected static ?string $navigationGroup = 'Ogłoszenia';
protected static ?string $navigationIcon = 'heroicon-o-newspaper';
protected static ?string $modelLabel = 'Artykuł';
protected static ?string $pluralModelLabel = 'Aktualności';
protected static ?int $navigationSort = 1;
public static function form(Form $form): Form
{
return $form
->schema([
Grid::make()
->schema([
Card::make()
->schema([
Forms\Components\TextInput::make('title')
->label('Tytuł')
->required()
->maxLength(2048)
->live(onBlur: true)
->afterStateUpdated(function (Set $set, ?string $state) {
$set('slug', Str::slug($state));
}),
Forms\Components\TextInput::make('slug')
->label('Przyjazny link')
->required()
->maxLength(2048),
Forms\Components\DateTimePicker::make('published_at')
->label('Data publikacji')
->native(false)
->displayFormat('d.m.Y')
->closeOnDateSelection()
->timezone('Europe/Warsaw')
->default(now())
->required(),
Forms\Components\FileUpload::make('thumbnail')
->label('Obraz')
->image()
->imageEditor()
->disk('public')
->directory('news-thumbnails')
->default(null),
Forms\Components\RichEditor::make('body')
->label('Treść')
->required()
->fileAttachmentsDisk('public')
->fileAttachmentsDirectory('news-content')
->fileAttachmentsVisibility('private')
->columnSpanFull(),
Forms\Components\Toggle::make('active')
->label('Aktywny')
->required(),
])
])->columnSpan(8),
Grid::make()
->schema([
Card::make()
->schema([
Select::make('attachments')
->multiple()
->required()
->label('Przypięte załączniki')
->nullable()
->placeholder('Wybierz załączniki')
->searchable()
->preload()
->reactive()
->relationship('attachments', 'file_name'),
]),
Card::make()
->schema([
Select::make('photos')
->multiple()
->required()
->label('Przypięte zdjęcia')
->nullable()
->placeholder('Wybierz zdjęcia')
->searchable()
->preload()
->reactive()
->relationship('photos', 'image_name'),
]),
])->columnSpan(8),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('title')
->label('Tytuł')
->searchable()
->limit(35)
->tooltip(function (Tables\Columns\TextColumn $column): ?string {
$state = $column->getState();
if (strlen($state) <= 35) {
return null;
}
return $state;
}),
Tables\Columns\ImageColumn::make('thumbnail')
->label('Obraz')
->searchable(),
Tables\Columns\IconColumn::make('active')
->label('Aktywny')
->boolean(),
Tables\Columns\TextColumn::make('published_at')
->label('Data publikacji')
->dateTime()
->sortable(),
])
->defaultSort('published_at', 'desc')
->description('Aktualności dostępne pod /aktualnosci i /aktualnosci/slug')
->filters([
//
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListArticleNews::route('/'),
'create' => Pages\CreateArticleNews::route('/create'),
'view' => Pages\ViewArticleNews::route('/{record}'),
'edit' => Pages\EditArticleNews::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Filament\Resources\ArticleNewsResource\Pages;
use App\Filament\Resources\ArticleNewsResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateArticleNews extends CreateRecord
{
protected static string $resource = ArticleNewsResource::class;
protected function mutateFormDataBeforeCreate(array $data): array
{
$data['user_id'] = auth()->id();
return $data;
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,299 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\ArticleResource\Pages;
use App\Filament\Resources\ArticleResource\RelationManagers;
use App\Models\Article;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Set;
use Illuminate\Support\Str;
use Filament\Forms\Components\Card;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Builder;
use Filament\Forms\Components\Textarea;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\IconColumn;
use App\Models\Attachment;
use App\Models\Photo;
use Illuminate\Support\Facades\Storage;
class ArticleResource extends Resource
{
public static function canAccess(): bool
{
return auth()->user()->can('manage_articles') || auth()->user()->can('admin');
}
protected static ?string $model = Article::class;
protected static ?string $navigationGroup = 'Treści';
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $modelLabel = 'Artykuł / Odnośnik';
protected static ?string $pluralModelLabel = 'Artykuły / Odnośniki';
protected static ?int $navigationSort = 1;
protected static ?array $articleTypes = ['article', 'article-with-map'];
public static function form(Form $form): Form
{
return $form
->extraAttributes(['style' => 'gap:0.5rem'])
->schema([
Card::make()
->schema([
// SELECT TYPE
Select::make('type')
->label("Rodzaj artykułu")
->required()
->default('article')
->options([
'article' => 'Artykuł',
'article-with-map' => 'Artykuł z mapą lokalizacyjną',
'link' => 'Odnośnik',
])
->reactive()
->afterStateUpdated(function (callable $set, $state) {
if ($state === 'link') {
$set('slug', null);
$set('body', null);
$set('active', false);
$set('external', false);
$set('thumbnail', null);
$set('attachments', null);
$set('photos', null);
$set('employees', null);
$set('additional_body', null);
$set('map_body', null);
} elseif (in_array($state, static::$articleTypes)) {
$set('body', null);
$set('active', false);
$set('external', false);
$set('attachments', null);
$set('photos', null);
$set('employees', null);
$set('additional_body', null);
$set('map_body', null);
}
}),
// END SELECT TYPE
// LINK TYPE
Card::make()
->hidden(fn ($get): bool => $get('type') != 'link')
->schema([
TextInput::make('title')
->label('Tytuł')
->required()
->maxLength(2048),
TextInput::make('slug')
->label('Ścieżka lub URL (np. /aktualnosci lub https://szpital.oborniki.info)')
->required()
->maxLength(2048),
Select::make('categories')
->multiple()
->label('Kategorie')
->nullable()
->placeholder('Wybierz kategorię')
->searchable()
->preload()
->reactive()
->relationship('categories', 'title'),
DateTimePicker::make('published_at')
->label('Data publikacji')
->native(false)
->displayFormat('d.m.Y')
->closeOnDateSelection()
->timezone('Europe/Warsaw'),
Grid::make()
->schema([
Toggle::make('active')
->label('Aktywny')
->required(),
Toggle::make('external')
->label('Otwieraj w nowej karcie')
->required(),
]),
]),
// END LINK TYPE
// ARTICLE TYPE
Grid::make()
->hidden(fn ($get): bool => !in_array($get('type'), static::$articleTypes))
->schema([
TextInput::make('title')
->label('Tytuł')
->required()
->maxLength(2048)
//->reactive() // this works without waiting but very slowly
//->live(debounce: 500) // wait 500 ms before update
->live(onBlur: true) // Update only after focus on other element
->afterStateUpdated(function (Set $set, ?string $state) {
$set('slug', Str::slug($state));
}),
TextInput::make('slug')
->label('Przyjazny link')
->required()
->maxLength(2048),
]),
RichEditor::make('body')
->label('Treść')
->hidden(fn ($get): bool => !in_array($get('type'), static::$articleTypes))
->required()
->fileAttachmentsDisk('public')
->fileAttachmentsDirectory('article-content')
->columnSpanFull(),
RichEditor::make('additional_body')
->label('Dodatkowa treść')
->hidden(fn ($get): bool => !in_array($get('type'), static::$articleTypes))
->fileAttachmentsDisk('public')
->fileAttachmentsDirectory('article-additional-content')
->columnSpanFull(),
RichEditor::make('map_body')
->label('Lokalizacja (widoczna pod mapą budynków)')
->hidden(fn ($get): bool => $get('type') != 'article-with-map')
->required()
->fileAttachmentsDisk('public')
->fileAttachmentsDirectory('article-map-content')
->columnSpanFull(),
Toggle::make('active')
->label('Aktywny')
->hidden(fn ($get): bool => !in_array($get('type'), static::$articleTypes))
->required(),
DateTimePicker::make('published_at')
->hidden(fn ($get): bool => !in_array($get('type'), static::$articleTypes))
->label('Data publikacji')
->native(false)
->displayFormat('d.m.Y')
->closeOnDateSelection()
->timezone('Europe/Warsaw'),
])->columnSpan(8),
Card::make()
->hidden(fn ($get): bool => !in_array($get('type'), static::$articleTypes))
->schema([
FileUpload::make('thumbnail')
->hidden(fn ($get): bool => $get('type') != 'article')
->label('Obraz')
->disk('public')
->directory('thumbnails')
->default(null),
Select::make('categories')
->multiple()
->label('Kategorie')
->nullable()
->placeholder('Wybierz kategorię')
->searchable()
->preload()
->reactive()
->relationship('categories', 'title'),
])->columnSpan(4),
Grid::make()
->hidden(fn ($get): bool => !in_array($get('type'), static::$articleTypes))
->schema([
Card::make()
->schema([
Select::make('attachments')
->multiple()
->required()
->label('Przypięte załączniki')
->nullable()
->placeholder('Wybierz załączniki')
->searchable()
->preload()
->reactive()
->relationship('attachments', 'file_name'),
]),
Card::make()
->schema([
Select::make('photos')
->multiple()
->required()
->label('Przypięte zdjęcia')
->nullable()
->placeholder('Wybierz zdjęcia')
->searchable()
->preload()
->reactive()
->relationship('photos', 'image_name'),
]),
])->columnSpan(8),
// END ARTICLE TYPE
])->columns(12);
}
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('type')
->label('Rodzaj')
->formatStateUsing(function ($state) {
return $state === 'article' ? 'Artykuł' : ($state === 'article-with-map' ? 'Artykuł z mapą' : 'Odnośnik');
}),
TextColumn::make('title')
->label('Tytuł')
->searchable()
->sortable(),
ImageColumn::make('thumbnail')
->label('Obraz'),
IconColumn::make('active')
->label('Aktywny')
->boolean(),
TextColumn::make('published_at')
->label('Data publikacji')
->dateTime('d.m.Y')
->sortable(),
TextColumn::make('user.name')
->label('Twórca')
->numeric(),
TextColumn::make('updated_at')
->label('Data aktualizacji')
->dateTime('d.m.Y')
->toggleable(isToggledHiddenByDefault: true),
])
->defaultSort('updated_at', 'desc')
->description('W tym miejscu możesz dodać, edytować oraz usuwać artykuły oraz odnośniki.')
->filters([
//
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListArticles::route('/'),
'create' => Pages\CreateArticle::route('/create'),
'view' => Pages\ViewArticle::route('/{record}'),
'edit' => Pages\EditArticle::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Filament\Resources\ArticleResource\Pages;
use App\Filament\Resources\ArticleResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateArticle extends CreateRecord
{
protected static string $resource = ArticleResource::class;
protected function mutateFormDataBeforeCreate(array $data): array
{
$data['user_id'] = auth()->id();
return $data;
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,142 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\AttachmentResource\Pages;
use App\Filament\Resources\AttachmentResource\RelationManagers;
use App\Models\Attachment;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Card;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;
use App\Models\Article;
class AttachmentResource extends Resource
{
public static function canAccess(): bool
{
return auth()->user()->can('manage_attachments') || auth()->user()->can('admin');
}
protected static ?string $model = Attachment::class;
protected static ?string $navigationIcon = 'heroicon-o-paper-clip';
protected static ?string $navigationGroup = 'Ogólne';
protected static ?string $modelLabel = 'Załącznik';
protected static ?string $pluralModelLabel = 'Załączniki';
protected static ?int $navigationSort = 2;
public static function form(Form $form): Form
{
return $form
->schema([
Grid::make()
->schema([
Card::make()
->schema([
FileUpload::make('file_path')
->disk('public')
->directory('attachments')
->label('Załącznik')
->required(),
TextInput::make('file_name')
->label('Nazwa')
->required(),
]),
Card::make()
->schema([
Select::make('articles')
->multiple()
->label('Przypięte artykuły')
->nullable()
->placeholder('Wybierz artykuły')
->searchable()
->preload()
->reactive()
->relationship('articles', 'title', fn ($query) => $query->whereIn('type', ['article', 'article-with-map'])),
]),
Card::make()
->schema([
Select::make('articlesNews')
->multiple()
->label('Przypięte aktualności')
->nullable()
->placeholder('Wybierz aktualności')
->searchable()
->preload()
->reactive()
->relationship('articlesNews', 'title'),
]),
Card::make()
->schema([
Select::make('jobOffers')
->multiple()
->label('Przypięte oferty pracy')
->nullable()
->placeholder('Wybierz oferty pracy')
->searchable()
->preload()
->reactive()
->relationship('jobOffers', 'title'),
]),
])->columnSpan(8),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('file_name')->label('Nazwa')
->limit(35)
->tooltip(function (Tables\Columns\TextColumn $column): ?string {
$state = $column->getState();
if (strlen($state) <= 35) {
return null;
}
return $state;
}),
Tables\Columns\TextColumn::make('file_path')->label('Załącznik'),
])
->filters([
//
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListAttachments::route('/'),
'create' => Pages\CreateAttachment::route('/create'),
'view' => Pages\ViewAttachment::route('/{record}'),
'edit' => Pages\EditAttachment::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\AttachmentResource\Pages;
use App\Filament\Resources\AttachmentResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateAttachment extends CreateRecord
{
protected static string $resource = AttachmentResource::class;
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,128 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\CategoryResource\Pages;
use App\Filament\Resources\CategoryResource\RelationManagers;
use App\Models\Category;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Set;
use Illuminate\Support\Str;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Hidden;
use App\Models\Article;
class CategoryResource extends Resource
{
public static function canAccess(): bool
{
return auth()->user()->can('manage_categories') || auth()->user()->can('admin');
}
protected static ?string $model = Category::class;
protected static ?string $navigationGroup = 'Treści';
protected static ?string $navigationIcon = 'heroicon-o-hashtag';
protected static ?string $modelLabel = 'Kategoria';
protected static ?string $pluralModelLabel = 'Kategorie';
protected static ?int $navigationSort = 2;
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('title')
->label('Tytuł')
->required()
->maxLength(2048)
->live(onBlur: true)
->afterStateUpdated(function (Set $set, ?string $state) {
$set('slug', Str::slug($state));
}),
TextInput::make('slug')
->label('Przyjazny link')
->required()
->maxLength(2048),
Repeater::make('articles')
->relationship('articles')
->schema([
Select::make('id')
->label('Artykuł / Odnośnik')
->options(Article::all()->pluck('title', 'id'))
->required()
->searchable()
->preload()
->reactive()
->disabled(true)
->default(null),
])
->orderColumn('sort_order')
->reorderableWithButtons()
->label('Artykuły w tej kategorii')
->visibleOn('edit')
->hidden(fn ($get) => empty($get('articles')))
->defaultItems(0)
->collapsible(false)
->deletable(false)
->addable(false)
->addActionLabel('Dodaj artykuł / odnośnik')
->itemLabel(fn (array $state): ?string => $state['id'] ? Article::find($state['id'])?->title : null)
->afterStateUpdated(function ($state, $record) {
if (!$record) return;
$state = collect($state)->values()->all();
foreach ($state as $index => $item) {
if (isset($item['id'])) {
\DB::table('category_article')
->where('category_id', $record->id)
->where('article_id', $item['id'])
->update(['sort_order' => $index]);
}
}
}),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('title')
->label('Tytuł')
->searchable(),
Tables\Columns\TextColumn::make('updated_at')
->label('Data aktualizacji')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->description('W tym miejscu możesz dodawać oraz usuwać kategorie, w trakcie edycjii możliwa jest zmiana kolejności artykułów.')
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getPages(): array
{
return [
'index' => Pages\ManageCategories::route('/'),
];
}
}

View File

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

View File

@@ -0,0 +1,134 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\DietResource\Pages;
use App\Filament\Resources\DietResource\RelationManagers;
use App\Models\Diet;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\Card;
class DietResource extends Resource
{
public static function canAccess(): bool
{
return auth()->user()->can('manage_diets') || auth()->user()->can('admin');
}
protected static ?string $model = Diet::class;
protected static ?string $navigationIcon = 'heroicon-o-building-storefront';
protected static ?string $navigationGroup = 'Pilotaż "Dobry posiłek"';
protected static ?string $modelLabel = 'Dieta';
protected static ?string $pluralModelLabel = 'Diety';
public static function form(Form $form): Form
{
return $form
->schema([
Card::make()
->schema([
Forms\Components\DateTimePicker::make('published_at')
->label('Data diety')
->native(false)
->displayFormat('d.m.Y')
->closeOnDateSelection()
->timezone('Europe/Warsaw')
->default(now())
->required(),
Forms\Components\TextInput::make('name')
->label('Nazwa')
->required()
->maxLength(2048),
Forms\Components\FileUpload::make('breakfast_photo')
->image()
->imageEditor()
->label('Zdjęcie śniadania')
->disk('public')
->directory('diets-photos')
->default(null),
Forms\Components\RichEditor::make('breakfast_body')
->label('Treść śniadania')
->columnSpanFull(),
Forms\Components\FileUpload::make('lunch_photo')
->image()
->imageEditor()
->label('Zdjęcie obiadu')
->disk('public')
->directory('diets-photos')
->default(null),
Forms\Components\RichEditor::make('lunch_body')
->label('Treść obiadu')
->columnSpanFull(),
Forms\Components\FileUpload::make('diet_attachment')
->label('Załącznik')
->disk('public')
->directory('diets-attachments')
->default(null),
Forms\Components\Toggle::make('active')
->label('Aktywny')
->required(),
])
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('name')
->label('Nazwa')
->searchable(),
Tables\Columns\ImageColumn::make('breakfast_photo')
->label('Zdjęcie śniadania')
->searchable(),
Tables\Columns\ImageColumn::make('lunch_photo')
->label('Zdjęcie obiadu')
->searchable(),
Tables\Columns\IconColumn::make('active')
->label('Aktywny')
->boolean(),
Tables\Columns\TextColumn::make('published_at')
->label('Data diety')
->dateTime('d.m.Y')
->sortable(),
])
->defaultSort('published_at', 'desc')
->defaultPaginationPageOption(20)
->filters([
//
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListDiets::route('/'),
'create' => Pages\CreateDiet::route('/create'),
'view' => Pages\ViewDiet::route('/{record}'),
'edit' => Pages\EditDiet::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Filament\Resources\DietResource\Pages;
use App\Filament\Resources\DietResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateDiet extends CreateRecord
{
protected static string $resource = DietResource::class;
protected function mutateFormDataBeforeCreate(array $data): array
{
$data['user_id'] = auth()->id();
return $data;
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,133 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\EmployeeResource\Pages;
use App\Filament\Resources\EmployeeResource\RelationManagers;
use App\Models\Employee;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\Builder;
use Filament\Forms\Components\Card;
use Filament\Forms\Components\TextInput;
use Filament\Tables\Actions\Action;
use Illuminate\Support\Str;
use Filament\Forms\Set;
class EmployeeResource extends Resource
{
public static function canAccess(): bool
{
return auth()->user()->can('manage_employees') || auth()->user()->can('admin');
}
protected static ?string $model = Employee::class;
protected static ?string $navigationIcon = 'heroicon-o-building-library';
protected static ?string $navigationGroup = 'Pozostałe';
protected static ?string $modelLabel = 'Pracownicy';
protected static ?string $pluralModelLabel = 'Pracownicy';
protected static ?int $navigationSort = 3;
public static function form(Form $form): Form
{
return $form
->schema([
Card::make()
->schema([
TextInput::make('section')
->label('Sekcja')
->required()
->maxLength(2048)
->live(onBlur: true)
->afterStateUpdated(function (Set $set, ?string $state) {
$set('slug', Str::slug($state));
}),
TextInput::make('slug')
->label('Przyjazny link')
->required()
->maxLength(2048),
]),
Card::make()
->schema([
Builder::make('employees')
->label('Pracownicy')
->blocks([
Builder\Block::make('employee')
->label('Pracownik')
->schema([
TextInput::make('other-section')
->label('Inna sekcja'),
TextInput::make('title')
->label('Stopień naukowy'),
TextInput::make('first_name')
->label('Imię')
->required(),
TextInput::make('last_name')
->label('Nazwisko')
->required(),
TextInput::make('position')
->label('Stanowisko')
->required(),
TextInput::make('email')
->label('E-mail'),
TextInput::make('phone')
->label('Telefon'),
])
->columns(2),
])
])
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('section')
->label('Sekcja')
->searchable(),
])
->defaultSort('sort_order')
->description('W tym miejscu możesz dodać, edytować oraz usuwać sekcje z administracją. Po utworzeniu sekcji pamiętaj o dodaniu jej do nawigacji jako odnośnika. Każda sekcja dostępna jest pod linkiem /administracja/slug')
->reorderable('sort_order')
->reorderRecordsTriggerAction(
fn (Action $action, bool $isReordering) => $action
->button()
->label($isReordering ? 'Wyłącz zmianę kolejności' : 'Zmień kolejność'),
)
->filters([
//
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListEmployees::route('/'),
'create' => Pages\CreateEmployee::route('/create'),
'view' => Pages\ViewEmployee::route('/{record}'),
'edit' => Pages\EditEmployee::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\EmployeeResource\Pages;
use App\Filament\Resources\EmployeeResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateEmployee extends CreateRecord
{
protected static string $resource = EmployeeResource::class;
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,163 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\JobOffersResource\Pages;
use App\Filament\Resources\JobOffersResource\RelationManagers;
use App\Models\JobOffers;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\Card;
use Filament\Forms\Components\Grid;
use Filament\Forms\Set;
use Illuminate\Support\Str;
use Filament\Forms\Components\Select;
class JobOffersResource extends Resource
{
public static function canAccess(): bool
{
return auth()->user()->can('manage_job_offers') || auth()->user()->can('admin');
}
protected static ?string $model = JobOffers::class;
protected static ?string $navigationGroup = 'Ogłoszenia';
protected static ?string $navigationIcon = 'heroicon-o-briefcase';
protected static ?string $modelLabel = 'Oferta pracy';
protected static ?string $pluralModelLabel = 'Oferty pracy';
protected static ?int $navigationSort = 2;
public static function form(Form $form): Form
{
return $form
->schema([
Grid::make()
->schema([
Card::make()
->schema([
Forms\Components\TextInput::make('title')
->label('Tytuł')
->required()
->maxLength(2048),
// ->live(onBlur: true)
// ->afterStateUpdated(function (Set $set, ?string $state) {
// $set('slug', Str::slug($state));
// }),
// Forms\Components\TextInput::make('slug')
// ->label('Przyjazny link')
// ->required()
// ->maxLength(2048),
Forms\Components\RichEditor::make('body')
->label('Treść')
->required()
->columnSpanFull(),
Forms\Components\Toggle::make('active')
->label('Aktywny')
->required(),
Forms\Components\DateTimePicker::make('published_at')
->label('Data publikacji')
->native(false)
->displayFormat('d.m.Y')
->closeOnDateSelection()
->timezone('Europe/Warsaw')
->default(now())
->required(),
])
])->columnSpan(8),
Grid::make()
->schema([
Card::make()
->schema([
Select::make('attachments')
->multiple()
->required()
->label('Przypięte załączniki')
->nullable()
->placeholder('Wybierz załączniki')
->searchable()
->preload()
->reactive()
->relationship('attachments', 'file_name'),
]),
// Card::make()
// ->schema([
// Select::make('photos')
// ->multiple()
// ->required()
// ->label('Pinned photos')
// ->nullable()
// ->placeholder('Select photos')
// ->searchable()
// ->preload()
// ->reactive()
// ->relationship('photos', 'image_name'),
// ]),
])->columnSpan(8),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('title')
->label('Tytuł')
->limit(35)
->tooltip(function (Tables\Columns\TextColumn $column): ?string {
$state = $column->getState();
if (strlen($state) <= 35) {
return null;
}
return $state;
})
->searchable()
->sortable(),
Tables\Columns\IconColumn::make('active')
->label('Aktywny')
->boolean(),
Tables\Columns\TextColumn::make('published_at')
->label('Data publikacji')
->dateTime()
->sortable(),
])
->defaultSort('published_at', 'desc')
->description('Aktualne rekrutacje dostępne pod /oferty-pracy')
->filters([
//
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListJobOffers::route('/'),
'create' => Pages\CreateJobOffers::route('/create'),
'view' => Pages\ViewJobOffers::route('/{record}'),
'edit' => Pages\EditJobOffers::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\JobOffersResource\Pages;
use App\Filament\Resources\JobOffersResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateJobOffers extends CreateRecord
{
protected static string $resource = JobOffersResource::class;
protected function mutateFormDataBeforeCreate(array $data): array
{
$data['user_id'] = auth()->id();
$data['slug'] = '/empty';
return $data;
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,153 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\NavigationItemResource\Pages;
use App\Models\NavigationItem;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Tables\Columns\TextColumn;
use App\Models\Article;
use App\Models\Category;
use Filament\Tables\Actions\Action;
class NavigationItemResource extends Resource
{
public static function canAccess(): bool
{
return auth()->user()->can('manage_navigation') || auth()->user()->can('admin');
}
protected static ?string $model = NavigationItem::class;
protected static ?string $navigationIcon = 'heroicon-o-bars-3';
protected static ?string $navigationGroup = 'Ogólne';
protected static ?string $modelLabel = 'Nawigacja';
protected static ?string $pluralModelLabel = 'Nawigacja';
protected static ?int $navigationSort = 1;
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('name')
->label('Nazwa (Opcjonalnie)')
->maxLength(255)
->default(null),
Select::make('navigable_type')
->label('Wybierz typ')
->default('Article')
->options([
'Article' => 'Artykuł / Odnośnik',
'Category' => 'Kategoria',
])
->reactive()
->afterStateUpdated(function (callable $set) {
$set('navigable_id', null);
})
->required(),
Select::make('navigable_id')
->label('Wybierz element')
->options(function ($get) {
if ($get('navigable_type') === 'Article') {
return Article::all()->mapWithKeys(function ($article) {
if ($article->type === 'link') {
return [$article->id => 'Odnośnik: ' . $article->title];
} else {
return [$article->id => 'Artykuł: ' . $article->title];
}
})->toArray();
} elseif ($get('navigable_type') === 'Category') {
return Category::all()->pluck('title', 'id')->mapWithKeys(function ($title, $id) {
return [$id => 'Kategoria: ' . $title];
})->toArray();
}
return [];
})
->reactive()
->searchable()
->required(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->getStateUsing(function ($record) {
if($record->name) return $record->name;
$type = $record->navigable_type;
$id = $record->navigable_id;
return match ($type) {
'Article' => Article::class::find($id)?->title ?? 'Artykuł / Odnośnik bez tytułu',
'Category' => Category::class::find($id)?->title ?? 'Kategoria bez tytułu',
default => $record->name,
};
})
->label('Nazwa')
->searchable(),
TextColumn::make('navigable_type')
->label('Typ')
->formatStateUsing(function ($record, $state) {
if($state === 'Article') {
$id = $record->navigable_id;
$type = Article::class::find($id)?->type;
if($type === 'link') {
return 'Odnośnik';
} else if($type === 'article') {
return 'Artykuł';
}
} else {
return 'Kategoria';
}
})
->searchable(),
])
->description('W tym miejscu możesz dodać Artykuł, Odnośnik lub Kategorię do nawigacji, możesz ustalać własną kolejność oraz nadawać niestandardowe nazwy.')
->reorderable('sort_order')
->defaultSort('sort_order')
->reorderRecordsTriggerAction(
fn (Action $action, bool $isReordering) => $action
->button()
->label($isReordering ? 'Wyłącz zmianę kolejności' : 'Zmień kolejność'),
)
->filters([
//
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListNavigationItems::route('/'),
'create' => Pages\CreateNavigationItem::route('/create'),
'view' => Pages\ViewNavigationItem::route('/{record}'),
'edit' => Pages\EditNavigationItem::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\NavigationItemResource\Pages;
use App\Filament\Resources\NavigationItemResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateNavigationItem extends CreateRecord
{
protected static string $resource = NavigationItemResource::class;
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,87 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\PermissionResource\Pages;
use App\Filament\Resources\PermissionResource\RelationManagers;
use Filament\Forms;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Spatie\Permission\Models\Permission;
class PermissionResource extends Resource
{
public static function canAccess(): bool
{
return auth()->user()->can('manage_permissions') || auth()->user()->can('admin');
}
protected static ?string $model = Permission::class;
protected static ?string $navigationIcon = 'heroicon-o-key';
protected static ?string $navigationGroup = 'Ustawienia';
protected static ?string $modelLabel = 'Uprawnienie';
protected static ?string $pluralModelLabel = 'Uprawnienia';
protected static ?int $navigationSort = 3;
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Section::make('Informacje o uprawnieniu')
->schema([
TextInput::make('name')
->label('Nazwa uprawnienia')
->required()
->maxLength(255)
->unique(ignoreRecord: true)
])
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->label('Nazwa uprawnienia')
->searchable(),
TextColumn::make('roles.name')
->label('Przypisane role')
->badge()
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListPermissions::route('/'),
'create' => Pages\CreatePermission::route('/create'),
'edit' => Pages\EditPermission::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\PermissionResource\Pages;
use App\Filament\Resources\PermissionResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreatePermission extends CreateRecord
{
protected static string $resource = PermissionResource::class;
}

View File

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

View File

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

View File

@@ -0,0 +1,138 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\PhotoResource\Pages;
use App\Filament\Resources\PhotoResource\RelationManagers;
use App\Models\Photo;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Card;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;
use App\Models\Article;
class PhotoResource extends Resource
{
public static function canAccess(): bool
{
return auth()->user()->can('manage_photos') || auth()->user()->can('admin');
}
protected static ?string $model = Photo::class;
protected static ?string $navigationIcon = 'heroicon-o-photo';
protected static ?string $navigationGroup = 'Ogólne';
protected static ?string $modelLabel = 'Zdjęcie';
protected static ?string $pluralModelLabel = 'Zdjęcia';
protected static ?int $navigationSort = 3;
public static function form(Form $form): Form
{
return $form
->schema([
Grid::make()
->schema([
Card::make()
->schema([
FileUpload::make('image_path')
->image()
->imageEditor()
->disk('public')
->directory('photos')
->label('Zdjęcie')
->required(),
TextInput::make('image_name')
->label('Nazwa')
->required(),
TextInput::make('image_desc')
->label('Opis (wykorzystywany w SEO)')
->required(),
]),
Card::make()
->schema([
Select::make('articles')
->multiple()
->label('Przypięte artykuły')
->nullable()
->placeholder('Wybierz artykuły')
->searchable()
->preload()
->reactive()
->relationship('articles', 'title', fn ($query) => $query->whereIn('type', ['article', 'article-with-map'])),
]),
Card::make()
->schema([
Select::make('articlesNews')
->multiple()
->label('Przypięte aktualności')
->nullable()
->placeholder('Wybierz aktualności')
->searchable()
->preload()
->reactive()
->relationship('articlesNews', 'title'),
]),
// Card::make()
// ->schema([
// Select::make('jobOffers')
// ->multiple()
// ->label('Pinned job offers')
// ->nullable()
// ->placeholder('Select job offers')
// ->searchable()
// ->preload()
// ->reactive()
// ->relationship('jobOffers', 'title'),
// ]),
])->columnSpan(8),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('image_name')->label('Nazwa')->limit(35),
Tables\Columns\TextColumn::make('image_desc')->label('Opis')->limit(35),
Tables\Columns\ImageColumn::make('image_path')->label('Zdjęcie'),
])
->filters([
//
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListPhotos::route('/'),
'create' => Pages\CreatePhoto::route('/create'),
'view' => Pages\ViewPhoto::route('/{record}'),
'edit' => Pages\EditPhoto::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\PhotoResource\Pages;
use App\Filament\Resources\PhotoResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreatePhoto extends CreateRecord
{
protected static string $resource = PhotoResource::class;
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,185 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\ProjectArticleResource\Pages;
use App\Filament\Resources\ProjectArticleResource\RelationManagers;
use App\Models\ProjectArticle;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Card;
use Filament\Forms\Components\Select;
use Illuminate\Support\Str;
use Filament\Forms\Set;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\TextInput;
class ProjectArticleResource extends Resource
{
public static function canAccess(): bool
{
return auth()->user()->can('manage_projects') || auth()->user()->can('admin');
}
protected static ?string $model = ProjectArticle::class;
protected static ?string $navigationGroup = 'Projekty';
protected static ?string $navigationIcon = 'heroicon-o-currency-dollar';
protected static ?string $modelLabel = 'Dofinansowanie';
protected static ?string $pluralModelLabel = 'Dofinansowania';
protected static ?int $navigationSort = 1;
public static function form(Form $form): Form
{
return $form
->extraAttributes(['style' => 'gap:0.5rem'])
->schema([
Card::make()
->schema([
Grid::make()
->schema([
TextInput::make('title')
->label('Nazwa')
->required()
->maxLength(2048)
->live(onBlur: true)
->afterStateUpdated(function (Set $set, ?string $state) {
$set('slug', Str::slug($state));
}),
TextInput::make('slug')
->label('Przyjazny link')
->required()
->maxLength(2048),
]),
FileUpload::make('logo')
->image()
->imageEditor()
->label('Logo')
->default(null),
RichEditor::make('body')
->label('Treść')
->fileAttachmentsDisk('public')
->fileAttachmentsDirectory('project-content')
->columnSpanFull(),
Toggle::make('active')
->label('Aktywny')
->required(),
DateTimePicker::make('published_at')
->label('Data publikacji')
->required(),
])->columnSpan(8),
Card::make()
->schema([
Select::make('projectTypes')
->multiple()
->required()
->label('Rodzaje dofinansowań')
->nullable()
->placeholder('Wybierz rodzaje dofinansowań')
->searchable()
->preload()
->reactive()
->relationship('projectTypes', 'title'),
Select::make('attachments')
->multiple()
->required()
->label('Przypięte załączniki')
->nullable()
->placeholder('Wybierz załączniki')
->searchable()
->preload()
->reactive()
->relationship('attachments', 'file_name'),
Select::make('photos')
->multiple()
->required()
->label('Przypięte zdjęcia')
->nullable()
->placeholder('Wybierz zdjęcia')
->searchable()
->preload()
->reactive()
->relationship('photos', 'image_name'),
])->columnSpan(4),
])->columns(12);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('title')
->label('Nazwa')
->searchable()
->limit(35)
->tooltip(function (Tables\Columns\TextColumn $column): ?string {
$state = $column->getState();
if (strlen($state) <= 35) {
return null;
}
return $state;
}),
Tables\Columns\TextColumn::make('projectTypes.title')
->label('Kategorie')
->limit(30)
->listWithLineBreaks()
->tooltip(function (Tables\Columns\TextColumn $column): ?string {
$state = $column->getState();
if (is_array($state) && strlen(implode(', ', $state)) <= 30) {
return null;
}
return is_array($state) ? implode(", ", $state) : $state;
}),
Tables\Columns\IconColumn::make('active')
->label('Aktywny')
->boolean(),
Tables\Columns\TextColumn::make('published_at')
->label('Data publikacji')
->dateTime()
->sortable(),
])
->defaultSort('published_at', 'desc')
->filters([
//
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListProjectArticles::route('/'),
'create' => Pages\CreateProjectArticle::route('/create'),
'view' => Pages\ViewProjectArticle::route('/{record}'),
'edit' => Pages\EditProjectArticle::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Filament\Resources\ProjectArticleResource\Pages;
use App\Filament\Resources\ProjectArticleResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateProjectArticle extends CreateRecord
{
protected static string $resource = ProjectArticleResource::class;
protected function mutateFormDataBeforeCreate(array $data): array
{
$data['user_id'] = auth()->id();
return $data;
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,126 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\ProjectTypeResource\Pages;
use App\Filament\Resources\ProjectTypeResource\RelationManagers;
use App\Models\ProjectType;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Card;
use Filament\Forms\Components\Select;
use Illuminate\Support\Str;
use Filament\Forms\Set;
class ProjectTypeResource extends Resource
{
public static function canAccess(): bool
{
return auth()->user()->can('manage_projects') || auth()->user()->can('admin');
}
protected static ?string $model = ProjectType::class;
protected static ?string $navigationGroup = 'Projekty';
protected static ?string $navigationIcon = 'heroicon-o-currency-dollar';
protected static ?string $modelLabel = 'Rodzaj dofinansowania';
protected static ?string $pluralModelLabel = 'Rodzaje dofinansowań';
protected static ?int $navigationSort = 2;
public static function form(Form $form): Form
{
return $form
->extraAttributes(['style' => 'gap:0.5rem'])
->schema([
Grid::make()
->schema([
Card::make()
->schema([
Forms\Components\TextInput::make('title')
->label('Nazwa')
->required()
->maxLength(2048)
->live(onBlur: true)
->afterStateUpdated(function (Set $set, ?string $state) {
$set('slug', Str::slug($state));
}),
Forms\Components\TextInput::make('slug')
->label('Przyjazny link')
->required()
->maxLength(2048),
]),
])->columnSpan(8),
Grid::make()
->schema([
Card::make()
->schema([
Select::make('projectArticles')
->multiple()
->required()
->label('Przypięte dofinansowania')
->nullable()
->placeholder('Wybierz dofinansowania')
->searchable()
->preload()
->reactive()
->relationship('projectArticles', 'title'),
]),
])->columnSpan(8),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('title')
->label('Nazwa')
->searchable(),
Tables\Columns\TextColumn::make('created_at')
->label('Data dodania')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->label('Data aktualizacji')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListProjectTypes::route('/'),
'create' => Pages\CreateProjectType::route('/create'),
'view' => Pages\ViewProjectType::route('/{record}'),
'edit' => Pages\EditProjectType::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\ProjectTypeResource\Pages;
use App\Filament\Resources\ProjectTypeResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateProjectType extends CreateRecord
{
protected static string $resource = ProjectTypeResource::class;
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,96 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\RoleResource\Pages;
use App\Filament\Resources\RoleResource\RelationManagers;
use Filament\Forms;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Spatie\Permission\Models\Role;
class RoleResource extends Resource
{
public static function canAccess(): bool
{
return auth()->user()->can('manage_roles') || auth()->user()->can('admin');
}
protected static ?string $model = Role::class;
protected static ?string $navigationIcon = 'heroicon-o-shield-check';
protected static ?string $navigationGroup = 'Ustawienia';
protected static ?string $modelLabel = 'Rola';
protected static ?string $pluralModelLabel = 'Role';
protected static ?int $navigationSort = 2;
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Section::make('Informacje o roli')
->schema([
TextInput::make('name')
->label('Nazwa roli')
->required()
->maxLength(255)
->unique(ignoreRecord: true),
Select::make('permissions')
->label('Uprawnienia')
->relationship('permissions', 'name')
->multiple()
->preload()
->searchable()
])
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->label('Nazwa roli')
->searchable(),
TextColumn::make('permissions.name')
->label('Uprawnienia')
->badge()
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListRoles::route('/'),
'create' => Pages\CreateRole::route('/create'),
'edit' => Pages\EditRole::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\RoleResource\Pages;
use App\Filament\Resources\RoleResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateRole extends CreateRecord
{
protected static string $resource = RoleResource::class;
}

View File

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

View File

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

View File

@@ -0,0 +1,113 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\TelephoneResource\Pages;
use App\Filament\Resources\TelephoneResource\RelationManagers;
use App\Models\Telephone;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\Card;
use Filament\Tables\Actions\Action;
use Filament\Forms\Components\Builder;
class TelephoneResource extends Resource
{
public static function canAccess(): bool
{
return auth()->user()->can('manage_telephones') || auth()->user()->can('admin');
}
protected static ?string $model = Telephone::class;
protected static ?string $navigationIcon = 'heroicon-o-phone';
protected static ?string $navigationGroup = 'Pozostałe';
protected static ?string $modelLabel = 'Telefony';
protected static ?string $pluralModelLabel = 'Telefony';
protected static ?int $navigationSort = 4;
public static function form(Form $form): Form
{
return $form
->schema([
Card::make()
->schema([
TextInput::make('section')
->label('Sekcja')
->required()
->maxLength(2048),
]),
Card::make()
->schema([
Builder::make('telephones')
->label('Telefony')
->blocks([
Builder\Block::make('telephone')
->label('Telefon')
->schema([
TextInput::make('name')
->label('Nazwa')
->required(),
TextInput::make('number')
->label('Numer')
->required(),
])
->columns(2),
])
])
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('section')
->label('Sekcja')
->searchable(),
])
->defaultSort('sort_order')
->description('W tym miejscu możesz dodać, edytować oraz usuwać sekcje z numerami telefonów.')
->reorderable('sort_order')
->reorderRecordsTriggerAction(
fn (Action $action, bool $isReordering) => $action
->button()
->label($isReordering ? 'Wyłącz zmianę kolejności' : 'Zmień kolejność'),
)
->filters([
//
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListTelephones::route('/'),
'create' => Pages\CreateTelephone::route('/create'),
'view' => Pages\ViewTelephone::route('/{record}'),
'edit' => Pages\EditTelephone::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\TelephoneResource\Pages;
use App\Filament\Resources\TelephoneResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateTelephone extends CreateRecord
{
protected static string $resource = TelephoneResource::class;
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,103 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\UserResource\Pages;
use App\Filament\Resources\UserResource\RelationManagers;
use App\Models\User;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Select;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Columns\TagsColumn;
class UserResource extends Resource
{
public static function canAccess(): bool
{
return auth()->user()->can('manage_users') || auth()->user()->can('admin');
}
protected static ?string $model = User::class;
protected static ?string $navigationIcon = 'heroicon-o-users';
protected static ?string $navigationGroup = 'Ustawienia';
protected static ?string $modelLabel = 'Administrator';
protected static ?string $pluralModelLabel = 'Administratorzy';
protected static ?int $navigationSort = 1;
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Section::make('Dane użytkownika')
->schema([
TextInput::make('name')
->label('Nazwa użytkownika')
->required(),
TextInput::make('email')
->label('Adres e-mail')
->email()
->required(),
TextInput::make('password')
->label('Hasło')
->password()
->required(fn ($livewire) => $livewire instanceof \Filament\Resources\Pages\CreateRecord)
->dehydrated(fn ($state) => filled($state))
->dehydrateStateUsing(fn ($state) => bcrypt($state)),
Select::make('roles')
->label('Role')
->relationship('roles', 'name')
->multiple()
->preload()
->searchable(),
])
->columns(2)
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')->label('Użytkownik')->searchable(),
TextColumn::make('email')->label('E-mail')->searchable(),
TagsColumn::make('roles.name')->label('Role'),
TextColumn::make('created_at')->label('Data utworzenia')->dateTime(),
])
->description('Dodawaj lub edytuj administratorów.')
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
//
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListUsers::route('/'),
'create' => Pages\CreateUser::route('/create'),
'edit' => Pages\EditUser::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\UserResource\Pages;
use App\Filament\Resources\UserResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateUser extends CreateRecord
{
protected static string $resource = UserResource::class;
}

View File

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

View File

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

View File

@@ -0,0 +1,119 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Article;
use App\Models\Location;
use App\Models\Attachment;
use App\Models\Photo;
use DOMDocument;
use DOMXPath;
class ArticleController extends Controller
{
private function cleanFileInfo(?string $html): ?string
{
if (!$html) {
return $html;
}
$dom = new DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
libxml_clear_errors();
$xpath = new DOMXPath($dom);
$figcaptions = $xpath->query('//figcaption');
foreach ($figcaptions as $figcaption) {
$figcaption->parentNode->removeChild($figcaption);
}
$imageLinks = $xpath->query('//a[.//img]');
foreach ($imageLinks as $link) {
$images = $xpath->query('.//img', $link);
$parent = $link->parentNode;
foreach ($images as $img) {
$link->removeChild($img);
$parent->insertBefore($img, $link);
}
$parent->removeChild($link);
}
return $dom->saveHTML();
}
public function index()
{
$slug = request('slug');
$query = Article::query();
$query->where('type', '!=', 'link')
->where('active', true);
if ($slug) {
$query->where('slug', $slug)->with(['photos', 'attachments', 'categories']);
}
$articles = $query->orderBy('published_at', 'desc')->get()->map(function ($item) {
if ($item->thumbnail && !str_starts_with($item->thumbnail, '/storage/')) {
$item->thumbnail = '/storage/' . ltrim($item->thumbnail, '/');
}
if ($item->photos) {
$item->photos->transform(function ($photo) {
if ($photo->image_path && !str_starts_with($photo->image_path, '/storage/')) {
$photo->image_path = '/storage/' . ltrim($photo->image_path, '/');
}
return $photo;
});
}
if ($item->attachments) {
$item->attachments->transform(function ($attachment) {
if ($attachment->file_path && !str_starts_with($attachment->file_path, '/storage/')) {
$attachment->file_path = '/storage/' . ltrim($attachment->file_path, '/');
}
return $attachment;
});
}
if ($item->type === 'article-with-map') {
$location = Location::first();
if ($location && $location->photo_id) {
$mapPhoto = Photo::where('id', $location->photo_id)->first();
if ($mapPhoto) {
if ($mapPhoto->image_path && !str_starts_with($mapPhoto->image_path, '/storage/')) {
$mapPhoto->image_path = '/storage/' . ltrim($mapPhoto->image_path, '/');
}
$item->map_photo = $mapPhoto;
}
}
}
if ($item->body) {
$item->body = $this->cleanFileInfo($item->body);
}
if ($item->additional_body) {
$item->additional_body = $this->cleanFileInfo($item->additional_body);
}
if ($item->map_body) {
$item->map_body = $this->cleanFileInfo($item->map_body);
}
return $item;
});
return response()->json([
'articles' => $articles,
]);
}
}

View File

@@ -0,0 +1,114 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\ArticleNews;
use DOMDocument;
use DOMXPath;
class ArticleNewsController extends Controller
{
private function cleanFileInfo(?string $html): ?string
{
if (!$html) {
return $html;
}
$dom = new DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
libxml_clear_errors();
$xpath = new DOMXPath($dom);
$figcaptions = $xpath->query('//figcaption');
foreach ($figcaptions as $figcaption) {
$figcaption->parentNode->removeChild($figcaption);
}
$imageLinks = $xpath->query('//a[.//img]');
foreach ($imageLinks as $link) {
$images = $xpath->query('.//img', $link);
$parent = $link->parentNode;
foreach ($images as $img) {
$link->removeChild($img);
$parent->insertBefore($img, $link);
}
$parent->removeChild($link);
}
return $dom->saveHTML();
}
public function index()
{
$slug = request('slug');
$page = request('page', 1);
$perPage = request('per_page', 10);
$query = ArticleNews::query()->where('active', true);
if ($slug) {
$query->where('slug', $slug)->with(['photos', 'attachments']);
$articleNews = $query->orderBy('published_at', 'desc')->get()->map(function ($item) {
if ($item->thumbnail && !str_starts_with($item->thumbnail, '/storage/')) {
$item->thumbnail = '/storage/' . ltrim($item->thumbnail, '/');
}
if ($item->photos) {
$item->photos->transform(function ($photo) {
if ($photo->image_path && !str_starts_with($photo->image_path, '/storage/')) {
$photo->image_path = '/storage/' . ltrim($photo->image_path, '/');
}
return $photo;
});
}
if ($item->attachments) {
$item->attachments->transform(function ($attachment) {
if ($attachment->file_path && !str_starts_with($attachment->file_path, '/storage/')) {
$attachment->file_path = '/storage/' . ltrim($attachment->file_path, '/');
}
return $attachment;
});
}
if ($item->body) {
$item->body = $this->cleanFileInfo($item->body);
}
return $item;
});
return response()->json([
'articleNews' => $articleNews,
]);
} else {
$total = $query->count();
$articleNews = $query->orderBy('published_at', 'desc')
->skip(($page - 1) * $perPage)
->take($perPage)
->get()
->map(function ($item) {
if ($item->thumbnail && !str_starts_with($item->thumbnail, '/storage/')) {
$item->thumbnail = '/storage/' . ltrim($item->thumbnail, '/');
}
return $item;
});
return response()->json([
'articleNews' => $articleNews,
'pagination' => [
'total' => $total,
'per_page' => $perPage,
'current_page' => $page,
'last_page' => ceil($total / $perPage),
],
]);
}
}
}

View File

@@ -0,0 +1,84 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Contact;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Validator;
class ContactController extends Controller
{
public function index()
{
$contact = Contact::first();
if (!$contact) {
return response()->json([
'message' => 'Nie znaleziono danych kontaktowych',
], 404);
}
return response()->json([
'contact' => $contact,
]);
}
public function sendMessage(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required|string|max:255',
'email' => 'required|email|max:255',
'subject' => 'required|string|max:255',
'message' => 'required|string',
'phone' => 'nullable|string|max:20',
'agreement' => 'required|boolean',
]);
if ($validator->fails()) {
if ($request->expectsJson() || $request->ajax() || $request->wantsJson()) {
return response()->json([
'message' => 'Błąd walidacji',
'errors' => $validator->errors(),
], 422);
}
return redirect()->back()->withErrors($validator)->withInput();
}
$contact = Contact::first();
$recipientEmail = $contact ? $contact->system_email : config('mail.from.address');
try {
Mail::to($recipientEmail)->send(new \App\Mail\ContactFormMail(
$request->name,
$request->email,
$request->subject,
$request->message,
$request->phone ?? null
));
$successMessage = 'Wiadomość została wysłana pomyślnie';
if ($request->expectsJson() || $request->ajax() || $request->wantsJson()) {
return response()->json([
'message' => $successMessage,
], 200);
}
return redirect()->route('contact')->with('success', $successMessage);
} catch (\Exception $e) {
$errorMessage = 'Wystąpił błąd podczas wysyłania wiadomości';
if ($request->expectsJson() || $request->ajax() || $request->wantsJson()) {
return response()->json([
'message' => $errorMessage,
'error' => $e->getMessage(),
], 500);
}
return redirect()->back()->with('error', $errorMessage)->withInput();
}
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Diet;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
class DietController extends Controller
{
public function index()
{
$page = request('page', 1);
$perPage = request('per_page', 7);
$query = Diet::query()->where('active', true);
$total = $query->count();
$diets = $query->orderBy('published_at', 'desc')
->skip(($page - 1) * $perPage)
->take($perPage)
->get()
->map(function ($diet) {
return $this->transformDiet($diet);
});
return response()->json([
'diets' => $diets,
'pagination' => [
'total' => $total,
'per_page' => (int)$perPage,
'current_page' => (int)$page,
'last_page' => ceil($total / $perPage),
],
]);
}
private function transformDiet($diet)
{
return [
'id' => $diet->id,
'name' => $diet->name,
'breakfast_photo' => $diet->breakfast_photo ? Storage::url($diet->breakfast_photo) : null,
'lunch_photo' => $diet->lunch_photo ? Storage::url($diet->lunch_photo) : null,
'breakfast_body' => $diet->breakfast_body,
'lunch_body' => $diet->lunch_body,
'published_at' => $diet->published_at,
'diet_attachment' => $diet->diet_attachment ? Storage::url($diet->diet_attachment) : null,
];
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Employee;
class EmployeeController extends Controller
{
public function index()
{
$slug = request('slug');
$query = Employee::query();
if ($slug) {
$query->where('slug', $slug);
}
$employees = $query->orderBy('sort_order')->get();
$mainSections = [];
$extraSections = [];
foreach ($employees as $employee) {
foreach ($employee->employees as $person) {
$targetSection = $person['data']['other-section'] ?? null;
if ($targetSection) {
if (!isset($extraSections[$targetSection])) {
$extraSections[$targetSection] = [
'name' => $targetSection,
'slug' => $employee->slug,
'sort_order' => $employee->sort_order,
'employees' => [],
];
}
$extraSections[$targetSection]['employees'][] = $person;
}
}
}
foreach ($employees as $employee) {
$mainPersons = array_filter($employee->employees, function($person) {
return empty($person['data']['other-section']);
});
if (count($mainPersons) === 0) continue;
$sectionName = $employee->section;
if (!isset($mainSections[$sectionName])) {
$mainSections[$sectionName] = [
'name' => $sectionName,
'slug' => $employee->slug,
'sort_order' => $employee->sort_order,
'employees' => [],
];
}
foreach ($mainPersons as $person) {
$mainSections[$sectionName]['employees'][] = $person;
}
}
return response()->json([
'main' => $mainSections,
'extra' => $extraSections,
]);
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Footer;
use App\Models\Article;
class FooterController extends Controller
{
public function index()
{
$footer = Footer::first();
$links = collect($footer?->links ?? [])
->filter(function ($item) {
return $item['type'] === 'link' && !empty($item['data']);
})
->map(function ($item) {
return [
'name' => $item['data']['name'] ?? '',
'url' => $item['data']['url'] ?? '#',
'external' => $item['data']['external'] ?? false,
];
})
->filter(function ($link) {
return !empty($link['name']) && !empty($link['url']);
})
->values()
->all();
$registration_hours = collect($footer?->registration_hours ?? [])
->filter(function ($item) {
return $item['type'] === 'registration_hour' && !empty($item['data']);
})
->map(function ($item) {
return [
'day' => $item['data']['day'] ?? '',
'hours' => $item['data']['hours'] ?? '',
];
})
->filter(function ($registration_hour) {
return !empty($registration_hour['day']) && !empty($registration_hour['hours']);
})
->values()
->all();
$wospArticleId = $footer?->wosp_link;
$wospArticleSlug = null;
if ($wospArticleId) {
$article = Article::with('categories')->find($wospArticleId);
if ($article) {
if ($article->categories->count() > 0) {
$firstCategory = $article->categories->first();
$wospArticleSlug = '/informacje/' . $firstCategory->slug . '/' . $article->slug;
} else {
$wospArticleSlug = '/informacje/' . $article->slug;
}
}
}
return response()->json([
'wosp_link' => $wospArticleSlug,
'registration_hours' => $registration_hours,
'links' => $links,
]);
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Header;
class HeaderController extends Controller
{
public function index()
{
$header = Header::first();
$links = collect($header?->links ?? [])
->filter(function ($item) {
return $item['type'] === 'link' && !empty($item['data']);
})
->map(function ($item) {
return [
'name' => $item['data']['name'] ?? '',
'icon' => $item['data']['icon'] ?? null,
'icon-alt' => $item['data']['icon-alt'] ?? null,
'url' => $item['data']['url'] ?? '#',
'external' => $item['data']['external'] ?? false,
];
})
->filter(function ($link) {
return !empty($link['name']) && !empty($link['url']);
})
->values()
->all();
return response()->json([
'title1' => $header?->title1,
'title2' => $header?->title2,
'subtitle' => $header?->subtitle,
'logo' => $header?->logo ? '/storage/' . $header->logo : null,
'telephone' => $header?->telephone,
'links' => $links,
]);
}
}

View File

@@ -0,0 +1,99 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Homepage;
use DOMDocument;
use DOMXPath;
class HomepageController extends Controller
{
private function cleanFileInfo(?string $html): ?string
{
if (!$html) {
return $html;
}
try {
$dom = new DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
libxml_clear_errors();
$xpath = new DOMXPath($dom);
$figcaptions = $xpath->query('//figcaption');
if ($figcaptions) {
foreach ($figcaptions as $figcaption) {
if ($figcaption && $figcaption->parentNode) {
$figcaption->parentNode->removeChild($figcaption);
}
}
}
$imageLinks = $xpath->query('//a[.//img]');
if ($imageLinks) {
foreach ($imageLinks as $link) {
if (!$link || !$link->parentNode) continue;
$images = $xpath->query('.//img', $link);
if (!$images) continue;
$parent = $link->parentNode;
foreach ($images as $img) {
if ($img) {
$link->removeChild($img);
$parent->insertBefore($img, $link);
}
}
$parent->removeChild($link);
}
}
return $dom->saveHTML();
} catch (\Exception $e) {
return $html;
}
}
public function index()
{
$homepage = Homepage::first();
$carouselPhotos = collect($homepage?->carousel_photos ?? [])
->filter(function ($item) {
return $item['type'] === 'carousel_photo' && !empty($item['data']);
})
->map(function ($item) {
return [
'name' => $item['data']['name'] ?? '',
'photo' => '/storage/' . $item['data']['photo'] ?? null,
'description' => $item['data']['description'] ?? null,
'url' => $item['data']['url'] ?? '#',
'external' => $item['data']['external'] ?? false,
];
})
->filter(function ($carousel_photo) {
return !empty($carousel_photo['name']) && !empty($carousel_photo['url']) && !empty($carousel_photo['photo']) && !empty($carousel_photo['description']);
})
->values()
->all();
$content = null;
if ($homepage && $homepage->content) {
try {
$content = $this->cleanFileInfo($homepage->content);
} catch (\Exception $e) {
$content = $homepage->content;
}
}
return response()->json([
'title' => $homepage?->title,
'content' => $content,
'photo' => $homepage?->photo ? '/storage/' . $homepage->photo : null,
'carouselPhotos' => $carouselPhotos,
]);
}
}

View File

@@ -0,0 +1,111 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\JobOffers;
use DOMDocument;
use DOMXPath;
class JobOffersController extends Controller
{
private function cleanFileInfo(?string $html): ?string
{
if (!$html) {
return $html;
}
try {
$dom = new DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
libxml_clear_errors();
$xpath = new DOMXPath($dom);
$figcaptions = $xpath->query('//figcaption');
if ($figcaptions) {
foreach ($figcaptions as $figcaption) {
if ($figcaption && $figcaption->parentNode) {
$figcaption->parentNode->removeChild($figcaption);
}
}
}
$imageLinks = $xpath->query('//a[.//img]');
if ($imageLinks) {
foreach ($imageLinks as $link) {
if (!$link || !$link->parentNode) continue;
$images = $xpath->query('.//img', $link);
if (!$images) continue;
$parent = $link->parentNode;
foreach ($images as $img) {
if ($img) {
$link->removeChild($img);
$parent->insertBefore($img, $link);
}
}
$parent->removeChild($link);
}
}
return $dom->saveHTML();
} catch (\Exception $e) {
return $html;
}
}
public function index()
{
$slug = request('slug');
$query = JobOffers::query()->where('active', true);
if ($slug) {
$query->where('slug', $slug);
}
$query->with(['photos', 'attachments']);
$jobOffers = $query->orderBy('published_at', 'desc')->get()->map(function ($item) {
if ($item->thumbnail && !str_starts_with($item->thumbnail, '/storage/')) {
$item->thumbnail = '/storage/' . ltrim($item->thumbnail, '/');
}
if ($item->photos) {
$item->photos->transform(function ($photo) {
if ($photo->image_path && !str_starts_with($photo->image_path, '/storage/')) {
$photo->image_path = '/storage/' . ltrim($photo->image_path, '/');
}
return $photo;
});
}
if ($item->attachments) {
$item->attachments->transform(function ($attachment) {
if ($attachment->file_path && !str_starts_with($attachment->file_path, '/storage/')) {
$attachment->file_path = '/storage/' . ltrim($attachment->file_path, '/');
}
return $attachment;
});
}
if ($item->body) {
$item->body = $this->cleanFileInfo($item->body);
}
if ($item->additional_information) {
$item->additional_information = $this->cleanFileInfo($item->additional_information);
}
return $item;
});
return response()->json([
'jobOffers' => $jobOffers
]);
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\NavigationItem;
use App\Models\Category;
use App\Models\Article;
class NavigationItemController extends Controller
{
public function index()
{
$items = NavigationItem::orderBy('sort_order')->get();
$result = $items->map(function ($item) {
$type = $item->navigable_type;
if ($type === 'Article') {
$article = Article::find($item->navigable_id);
$name = $item->name ?? ($article ? $article->title : null);
if ($article && $article->type !== 'link' && $article->slug) {
$articleWithCategories = Article::with('categories')->find($article->id);
if ($articleWithCategories->categories->count() > 0) {
$firstCategory = $articleWithCategories->categories->first();
$article->slug = '/informacje/' . $firstCategory->slug . '/' . ltrim($article->slug, '/');
} else {
$article->slug = '/informacje/' . ltrim($article->slug, '/');
}
}
return [
'id' => $item->id,
'name' => $name,
'sort_order' => $item->sort_order,
'type' => 'article',
'article' => $article,
];
} elseif ($type === 'Category') {
$category = Category::find($item->navigable_id);
$articles = $category
? $category->articles()->orderBy('category_article.sort_order')->get()->map(function($article) use ($category) {
if ($article->type !== 'link' && $article->slug) {
$article->slug = '/informacje/' . $category->slug . '/' . ltrim($article->slug, '/');
}
return $article;
})
: [];
$name = $item->name ?? ($category ? $category->title : null);
return [
'id' => $item->id,
'name' => $name,
'sort_order' => $item->sort_order,
'type' => 'category',
'articles' => $articles,
];
} else {
return [
'id' => $item->id,
'name' => $item->name,
'sort_order' => $item->sort_order,
'type' => $type
];
}
});
return response()->json($result);
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Attachment;
use App\Models\Price;
use App\Models\Article;
class PriceController extends Controller
{
public function index()
{
$price = Price::first();
$attachment = null;
$categoryTitle = null;
if ($price && $price->attachment_id) {
$attachment = Attachment::find($price->attachment_id);
if ($attachment && $attachment->file_path && !str_starts_with($attachment->file_path, '/storage/')) {
$attachment->file_path = '/storage/' . ltrim($attachment->file_path, '/');
}
}
$priceArticle = Article::where('type', 'link')
->where(function($query) {
$query->where('slug', 'like', '/cennik-badan');
})
->first();
if ($priceArticle) {
$categories = $priceArticle->categories;
if ($categories && $categories->count() > 0) {
$categoryTitle = $categories->first()->title;
} else {
$categoryTitle = null;
}
}
return response()->json([
'attachment' => $attachment,
'category' => $categoryTitle
]);
}
}

View File

@@ -0,0 +1,156 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\ProjectArticle;
use App\Models\ProjectType;
use Illuminate\Http\Request;
use DOMDocument;
use DOMXPath;
class ProjectController extends Controller
{
private function cleanFileInfo(?string $html): ?string
{
if (!$html) {
return $html;
}
$dom = new DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
libxml_clear_errors();
$xpath = new DOMXPath($dom);
$figcaptions = $xpath->query('//figcaption');
foreach ($figcaptions as $figcaption) {
$figcaption->parentNode->removeChild($figcaption);
}
$imageLinks = $xpath->query('//a[.//img]');
foreach ($imageLinks as $link) {
$images = $xpath->query('.//img', $link);
$parent = $link->parentNode;
foreach ($images as $img) {
$link->removeChild($img);
$parent->insertBefore($img, $link);
}
$parent->removeChild($link);
}
return $dom->saveHTML();
}
public function index(Request $request, $typeSlug = null)
{
$query = ProjectArticle::query()
->where('active', true)
->with(['projectTypes', 'photos', 'attachments']);
if ($typeSlug) {
$projectType = ProjectType::where('slug', $typeSlug)->first();
if ($projectType) {
$query->whereHas('projectTypes', function ($q) use ($projectType) {
$q->where('project_types.id', $projectType->id);
});
}
}
$projects = $query->orderBy('published_at', 'desc')
->get()
->map(function ($item) {
if ($item->logo && !str_starts_with($item->logo, '/storage/')) {
$item->logo = '/storage/' . ltrim($item->logo, '/');
}
if ($item->photos) {
$item->photos->transform(function ($photo) {
if ($photo->image_path && !str_starts_with($photo->image_path, '/storage/')) {
$photo->image_path = '/storage/' . ltrim($photo->image_path, '/');
}
return $photo;
});
}
if ($item->attachments) {
$item->attachments->transform(function ($attachment) {
if ($attachment->file_path && !str_starts_with($attachment->file_path, '/storage/')) {
$attachment->file_path = '/storage/' . ltrim($attachment->file_path, '/');
}
return $attachment;
});
}
if ($item->body) {
$item->body = $this->cleanFileInfo($item->body);
}
return $item;
});
return response()->json([
'projects' => $projects,
'projectType' => $typeSlug ? ProjectType::where('slug', $typeSlug)->first() : null
]);
}
public function show(Request $request, $typeSlug, $projectSlug)
{
$projectType = ProjectType::where('slug', $typeSlug)->first();
if (!$projectType) {
return response()->json([
'error' => 'Nie znaleziono typu projektu'
], 404);
}
$project = ProjectArticle::where('slug', $projectSlug)
->where('active', true)
->whereHas('projectTypes', function ($query) use ($projectType) {
$query->where('project_types.id', $projectType->id);
})
->with(['projectTypes', 'photos', 'attachments'])
->first();
if (!$project) {
return response()->json([
'error' => 'Nie znaleziono projektu'
], 404);
}
if ($project->logo && !str_starts_with($project->logo, '/storage/')) {
$project->logo = '/storage/' . ltrim($project->logo, '/');
}
if ($project->photos) {
$project->photos->transform(function ($photo) {
if ($photo->image_path && !str_starts_with($photo->image_path, '/storage/')) {
$photo->image_path = '/storage/' . ltrim($photo->image_path, '/');
}
return $photo;
});
}
if ($project->attachments) {
$project->attachments->transform(function ($attachment) {
if ($attachment->file_path && !str_starts_with($attachment->file_path, '/storage/')) {
$attachment->file_path = '/storage/' . ltrim($attachment->file_path, '/');
}
return $attachment;
});
}
if ($project->body) {
$project->body = $this->cleanFileInfo($project->body);
}
return response()->json([
'project' => $project,
'projectType' => $projectType
]);
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Telephone;
use Illuminate\Http\Request;
class TelephoneController extends Controller
{
public function index()
{
$telephones = Telephone::orderBy('sort_order', 'asc')->get();
return response()->json([
'telephones' => $telephones,
]);
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace App\Http\Controllers;
abstract class Controller
{
//
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\View;
use Symfony\Component\HttpFoundation\Response;
class HandleAppearance
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
View::share('appearance', $request->cookie('appearance') ?? 'system');
return $next($request);
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Inspiring;
use Illuminate\Http\Request;
use Inertia\Middleware;
use Tighten\Ziggy\Ziggy;
class HandleInertiaRequests extends Middleware
{
/**
* The root template that's loaded on the first page visit.
*
* @see https://inertiajs.com/server-side-setup#root-template
*
* @var string
*/
protected $rootView = 'app';
/**
* Determines the current asset version.
*
* @see https://inertiajs.com/asset-versioning
*/
public function version(Request $request): ?string
{
return parent::version($request);
}
/**
* Define the props that are shared by default.
*
* @see https://inertiajs.com/shared-data
*
* @return array<string, mixed>
*/
public function share(Request $request): array
{
[$message, $author] = str(Inspiring::quotes()->random())->explode('-');
return [
...parent::share($request),
'name' => config('app.name'),
'quote' => ['message' => trim($message), 'author' => trim($author)],
'auth' => [
'user' => $request->user(),
],
'ziggy' => fn (): array => [
...(new Ziggy)->toArray(),
'location' => $request->url(),
],
'sidebarOpen' => ! $request->hasCookie('sidebar_state') || $request->cookie('sidebar_state') === 'true',
];
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class ContactFormMail extends Mailable
{
use Queueable, SerializesModels;
/**
* Data from the contact form
*/
public $name;
public $email;
public $userSubject;
public $messageContent;
public $phone;
/**
* Create a new message instance.
*/
public function __construct(
string $name,
string $email,
string $subject,
string $message,
?string $phone = null
) {
$this->name = $name;
$this->email = $email;
$this->userSubject = $subject;
$this->messageContent = $message;
$this->phone = $phone;
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Wiadomość z formularza kontaktowego',
replyTo: $this->email,
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'emails.contact-form',
with: [
'name' => $this->name,
'email' => $this->email,
'subject' => $this->userSubject,
'messageContent' => $this->messageContent,
'phone' => $this->phone,
],
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}

40
app/Models/Article.php Normal file
View File

@@ -0,0 +1,40 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
class Article extends Model
{
protected $fillable = ['title', 'slug', 'thumbnail', 'body', 'active', 'published_at', 'user_id', 'type', 'category_id', 'external', 'additional_body', 'map_body'];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function categories(): BelongsToMany
{
return $this->belongsToMany(Category::class, 'category_article')
->using(CategoryArticle::class)
->withPivot('sort_order');
}
public function navigationItems(): MorphMany
{
return $this->morphMany(NavigationItem::class, 'navigable');
}
public function attachments(): BelongsToMany
{
return $this->belongsToMany(Attachment::class, 'article_attachment');
}
public function photos(): BelongsToMany
{
return $this->belongsToMany(Photo::class, 'article_photo');
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class ArticleAttachment extends Model
{
protected $table = 'article_attachment';
protected $fillable = [
'article_id',
'attachment_id',
];
use HasFactory;
}

View File

@@ -0,0 +1,37 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class ArticleNews extends Model
{
protected $table = 'article_news';
protected $fillable = [
'title',
'slug',
'thumbnail',
'body',
'active',
'published_at',
'user_id',
];
public function attachments(): BelongsToMany
{
return $this->belongsToMany(Attachment::class, 'article_news_attachment');
}
public function photos(): BelongsToMany
{
return $this->belongsToMany(Photo::class, 'article_news_photo');
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class ArticleNewsAttachment extends Model
{
protected $table = 'article_news_attachment';
protected $fillable = [
'article_news_id',
'attachment_id',
];
use HasFactory;
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ArticleNewsPhoto extends Model
{
protected $table = 'article_news_photo';
protected $fillable = [
'article_news_id',
'photo_id',
];
use HasFactory;
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ArticlePhoto extends Model
{
protected $table = 'article_photo';
protected $fillable = [
'article_id',
'photo_id',
];
use HasFactory;
}

31
app/Models/Attachment.php Normal file
View File

@@ -0,0 +1,31 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Attachment extends Model
{
protected $fillable = ['file_name', 'file_path'];
public function articles(): BelongsToMany
{
return $this->belongsToMany(Article::class, 'article_attachment');
}
public function articlesNews(): BelongsToMany
{
return $this->belongsToMany(ArticleNews::class, 'article_news_attachment');
}
public function jobOffers(): BelongsToMany
{
return $this->belongsToMany(JobOffers::class, 'job_offers_attachment');
}
public function projectArticles(): BelongsToMany
{
return $this->belongsToMany(ProjectArticle::class, 'project_article_attachment');
}
}

Some files were not shown because too many files have changed in this diff Show More