ÿþ<?php namespace App\Filament\Resources; use App\Filament\Resources\BannerResource\Pages; use App\Models\Banner; use Filament\Forms; use Filament\Forms\Form; use Filament\Resources\Resource; use Filament\Tables; use Filament\Tables\Table; class BannerResource extends Resource { protected static ?string $model = Banner::class; protected static ?string $navigationIcon = 'ri-gallery-line'; protected static ?string $navigationGroup = 'App Management'; protected static ?int $navigationSort = 0; public static function form(Form $form): Form { return $form ->schema([ Forms\Components\FileUpload::make('path') ->required() ->image() ->imageEditor() ->columnSpanFull() ->helperText(function (Forms\Get $get) { $path = $get('path'); if (blank($path)) { return 'Rekomendasi dimensi: 1920%ù1080 px (16:9)'; } $file = is_array($path) ? ($path[0] ?? null) : $path; if (! is_string($file)) { return 'Rekomendasi dimensi: 1920%ù1080 px (16:9)'; } $full = storage_path('app/public/'.ltrim($file, '/')); if (is_file($full)) { $size = @getimagesize($full); if ($size && isset($size[0], $size[1])) { return 'Dimensi saat ini: '.$size[0].'%ù'.$size[1].' px'; } } return 'Rekomendasi dimensi: 1920%ù1080 px (16:9)'; }), Forms\Components\TextInput::make('name') ->required() ->maxLength(255), Forms\Components\TextInput::make('redirect') ->label('Redirect URL') ->url() ->maxLength(255), ]); } public static function table(Table $table): Table { return $table ->reorderable('sort') ->columns([ Tables\Columns\ImageColumn::make('path') ->label('Image'), Tables\Columns\TextColumn::make('name') ->searchable(), Tables\Columns\TextColumn::make('redirect') ->label('Redirect URL') ->default('Redirect Disabled') ->searchable(), Tables\Columns\TextColumn::make('created_at') ->dateTime() ->sortable() ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('updated_at') ->dateTime() ->sortable() ->toggleable(isToggledHiddenByDefault: true), ]) ->defaultSort('sort') ->filters([ // ]) ->actions([ Tables\Actions\ActionGroup::make([ Tables\Actions\EditAction::make(), Tables\Actions\DeleteAction::make(), ]), ]) ->headerActions([ Tables\Actions\CreateAction::make() ->label('Create Banner'), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), ]), ]); } public static function getRelations(): array { return [ // ]; } public static function getPages(): array { return [ 'index' => Pages\ListBanners::route('/'), // 'create' => Pages\CreateBanner::route('/create'), // 'edit' => Pages\EditBanner::route('/{record}/edit'), ]; } } ÿþ<?php namespace App\Filament\Resources; use App\Filament\Resources\EventResource\Pages; use App\Filament\Resources\EventResource\Pages\EditEvent; use App\Filament\Resources\EventResource\Pages\ManageEventTickets; use App\Filament\Resources\EventResource\Pages\ManageEventTransactions; use App\Filament\Resources\EventResource\Pages\ViewEvent; use App\Filament\Resources\EventResource\RelationManagers\TicketsRelationManager; use App\Models\Event; use AymanAlhattami\FilamentPageWithSidebar\FilamentPageSidebar; use AymanAlhattami\FilamentPageWithSidebar\PageNavigationItem; use Carbon\Carbon; use Filament\Forms; use Filament\Forms\Components\Section; use Filament\Forms\Form; use Filament\Forms\Set; use Filament\Resources\Resource; use Filament\Support\Enums\Alignment; use Filament\Tables; use Filament\Tables\Actions\ActionGroup; use Filament\Tables\Filters\Indicator; use Filament\Tables\Filters\SelectFilter; use Filament\Tables\Table; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Str; class EventResource extends Resource { protected static ?string $model = Event::class; protected static ?string $navigationIcon = 'ri-calendar-event-line'; protected static ?string $navigationGroup = 'Event Management'; protected static ?string $recordTitleAttribute = 'name'; protected static ?int $navigationSort = 0; public static function form(Form $form): Form { return $form ->schema([ Section::make('Event Banner') ->schema([ Forms\Components\FileUpload::make('cover') ->label('Upload Event Banner') ->required() ->image() ->imageEditor() ->columnSpanFull() ->helperText(function (Forms\Get $get) { $path = $get('cover'); if (blank($path)) { return 'Rekomendasi dimensi: 1920%ù1080 px (16:9)'; } $file = is_array($path) ? ($path[0] ?? null) : $path; if (! is_string($file)) { return 'Rekomendasi dimensi: 1920%ù1080 px (16:9)'; } $full = storage_path('app/public/'.ltrim($file, '/')); if (is_file($full)) { $size = @getimagesize($full); if ($size && isset($size[0], $size[1])) { return 'Dimensi saat ini: '.$size[0].'%ù'.$size[1].' px'; } } return 'Rekomendasi dimensi: 1920%ù1080 px (16:9)'; }), ]), Section::make('Event Information')->schema([ Forms\Components\TextInput::make('name') ->label('Event Name') ->required() ->maxLength(255) ->live(onBlur: true) ->afterStateUpdated(function (Set $set, $state) { $set('slug', Str::slug($state)); }), Forms\Components\TextInput::make('location') ->label('Event Location') ->placeholder('Venue Name, City, Country') ->required(), Forms\Components\RichEditor::make('description') ->required() ->columnSpanFull(), Forms\Components\DatePicker::make('startDate') ->label('Event Start Date') ->native(false), Forms\Components\DatePicker::make('endDate') ->label('Event End Date') ->native(false), Forms\Components\TextInput::make('coordinates') ->label('Map Coordinates') ->placeholder('0.000000, 0.000000') ->required(), Forms\Components\Select::make('category_id') ->label('Event Category') ->relationship(name: 'category', titleAttribute: 'name') ->createOptionForm([ Forms\Components\TextInput::make('name') ->label('Category Name') ->required() ->live(onBlur: true) ->afterStateUpdated(function (Set $set, $state) { $set('slug', Str::slug($state)); }), Forms\Components\TextInput::make('slug') ->required(), ]) ->preload() ->searchable() ->selectablePlaceholder(false) ->loadingMessage('Loading categories...') ->noSearchResultsMessage('No categories found.') ->searchPrompt('Search Event Categories') ->placeholder('') ->native(false), Forms\Components\TextInput::make('slug') ->required() ->maxLength(255), ]), ]); } public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\ImageColumn::make('cover') ->label('Event Banner'), Tables\Columns\TextColumn::make('name') ->sortable() ->searchable(), Tables\Columns\TextColumn::make('description') ->limit(50) ->html() ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('category.name') ->label('Event Category') ->searchable() ->sortable(), Tables\Columns\TextColumn::make('startDate') ->date() ->sortable(), Tables\Columns\TextColumn::make('endDate') ->date() ->sortable(), Tables\Columns\ToggleColumn::make('isAvailable') ->label('Availability') ->alignment(Alignment::Center), Tables\Columns\TextColumn::make('slug') ->searchable() ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('created_at') ->dateTime() ->sortable() ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('updated_at') ->dateTime() ->sortable() ->toggleable(isToggledHiddenByDefault: true), ]) ->defaultSort('name') ->filters([ SelectFilter::make('category.name') ->relationship(name: 'category', titleAttribute: 'name') ->searchable() ->preload() ->native(false), Tables\Filters\Filter::make('startDate') ->form([ Forms\Components\DatePicker::make('startDate')->native(false)->label('Started From'), ]) ->query(function (Builder $query, array $data): Builder { return $query ->when( $data['startDate'], fn (Builder $query, $date): Builder => $query->whereDate('startDate', '>=', $date), ); }) ->indicateUsing(function (array $data): array { $indicators = []; if ($data['startDate'] ?? null) { $indicators[] = Indicator::make('Created from '.Carbon::parse($data['startDate'])->toFormattedDateString()) ->removeField('startDate'); } return $indicators; }), Tables\Filters\Filter::make('endDate') ->form([ Forms\Components\DatePicker::make('endDate')->native(false)->label('Created Until'), ]) ->query(function (Builder $query, array $data): Builder { return $query ->when( $data['endDate'], fn (Builder $query, $date): Builder => $query->whereDate('endDate', '<=', $date), ); }) ->indicateUsing(function (array $data): array { $indicators = []; if ($data['endDate'] ?? null) { $indicators[] = Indicator::make('Created until '.Carbon::parse($data['endDate'])->toFormattedDateString()) ->removeField('endDate'); } return $indicators; }), ]) ->filtersTriggerAction( fn (Tables\Actions\Action $action) => $action ->button() ->label('Filter'), ) ->actions([ ActionGroup::make([ Tables\Actions\ViewAction::make() ->modalHeading(fn (Event $event) => 'Viewing '.$event->name), Tables\Actions\EditAction::make() ->modalHeading(fn (Event $event) => 'Editing '.$event->name), Tables\Actions\DeleteAction::make() ->modalHeading(fn (Event $event) => 'Delete '.$event->name.'?'), ]), ]) ->headerActions([ Tables\Actions\CreateAction::make() ->label('Create Event') ->modalHeading('Creating Event'), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), ]), ]); } public static function getRelations(): array { return [ // TicketsRelationManager::class ]; } public static function getPages(): array { return [ 'index' => Pages\ListEvents::route('/'), 'view' => Pages\ViewEvent::route('/{record}/view'), 'edit' => Pages\EditEvent::route('/{record}/edit'), 'tickets' => Pages\ManageEventTickets::route('/{record}/tickets'), 'transactions' => Pages\ManageEventTransactions::route('/{record}/transactions'), ]; } public static function sidebar(Event $record): FilamentPageSidebar { return FilamentPageSidebar::make() ->setTitle('Event Details') ->setNavigationItems([ self::createSidebarItem('View Event', 'view', '', $record, ViewEvent::class), self::createSidebarItem('Edit Event', 'edit', '', $record, EditEvent::class), self::createSidebarItem('Manage Tickets', 'tickets', 'ri-coupon-line', $record, ManageEventTickets::class), self::createSidebarItem('Manage Transactions', 'transactions', 'ri-shopping-cart-2-line', $record, ManageEventTransactions::class), ]); } private static function createSidebarItem(string $label, string $action, string $icon, Event $record, string $routeClass): PageNavigationItem { return PageNavigationItem::make($label) ->url(static::getUrl($action, ['record' => $record->id])) ->icon($icon ? $icon : 'ri-folders-line') ->isActiveWhen(fn () => request()->routeIs($routeClass::getRouteName())); } } ÿþ<?php namespace App\Filament\Resources\EventResource\Pages; use App\Filament\Resources\EventResource; use AymanAlhattami\FilamentPageWithSidebar\Traits\HasPageSidebar; use Filament\Forms; use Filament\Forms\Form; use Filament\Resources\Pages\ManageRelatedRecords; use Filament\Support\Enums\Alignment; use Filament\Tables; use Filament\Tables\Table; class ManageEventTickets extends ManageRelatedRecords { use HasPageSidebar; protected static string $resource = EventResource::class; protected static string $relationship = 'tickets'; protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack'; public static function getNavigationLabel(): string { return 'Tickets'; } public function form(Form $form): Form { return $form ->schema([ Forms\Components\Section::make('Ticket Image') ->schema([ Forms\Components\FileUpload::make('cover') ->label('Upload Ticket Image') ->image() ->imageEditor() ->columnSpanFull() ->helperText(function (Forms\Get $get) { $path = $get('cover'); if (blank($path)) { return 'Rekomendasi dimensi: 1280%ù720 px (16:9)'; } $file = is_array($path) ? ($path[0] ?? null) : $path; if (! is_string($file)) { return 'Rekomendasi dimensi: 1280%ù720 px (16:9)'; } $full = storage_path('app/public/'.ltrim($file, '/')); if (is_file($full)) { $size = @getimagesize($full); if ($size && isset($size[0], $size[1])) { return 'Dimensi saat ini: '.$size[0].'%ù'.$size[1].' px'; } } return 'Rekomendasi dimensi: 1280%ù720 px (16:9)'; }), Forms\Components\FileUpload::make('layout') ->label('Upload Ticket Downloadable Layout') ->image() ->imageEditor() ->columnSpanFull() ->helperText(function (Forms\Get $get) { $path = $get('layout'); if (blank($path)) { return 'Rekomendasi dimensi: 2480%ù3508 px (A4 portrait, 300 DPI)'; } $file = is_array($path) ? ($path[0] ?? null) : $path; if (! is_string($file)) { return 'Rekomendasi dimensi: 2480%ù3508 px (A4 portrait, 300 DPI)'; } $full = storage_path('app/public/'.ltrim($file, '/')); if (is_file($full)) { $size = @getimagesize($full); if ($size && isset($size[0], $size[1])) { return 'Dimensi saat ini: '.$size[0].'%ù'.$size[1].' px'; } } return 'Rekomendasi dimensi: 2480%ù3508 px (A4 portrait, 300 DPI)'; }), ]), Forms\Components\Section::make('Ticket Information') ->schema([ Forms\Components\TextInput::make('name') ->label('Ticket Name') ->required() ->maxLength(255), Forms\Components\Select::make('type') ->label('Ticket Type') ->required() ->options([ 'Regular' => 'Regular', 'Pre-Sale' => 'Pre-Sale', 'Early Bird' => 'Early Bird', ]) ->native(false), Forms\Components\TextInput::make('price') ->required() ->numeric() ->prefix('IDR'), Forms\Components\TextInput::make('quantity') ->label('Scanable Credit') ->helperText('Amount of the ticket can be scan on the venue.') ->numeric() ->required() ->maxLength(255), Forms\Components\DatePicker::make('startValidDate') ->required() ->native(false), Forms\Components\DatePicker::make('endValidDate') ->required() ->native(false), ])->columns(2), ]); } public function table(Table $table): Table { return $table ->recordTitleAttribute('name') ->columns([ Tables\Columns\TextColumn::make('name') ->label('Ticket Type') ->sortable(), Tables\Columns\TextColumn::make('price') ->label('Price') ->sortable() ->money('IDR'), Tables\Columns\TextColumn::make('startValidDate') ->label('Valid From') ->date() ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('endValidDate') ->label('Valid Until') ->date() ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('generated_tickets_count') ->label('Total Sold') ->counts('generatedTickets') ->searchable() ->alignCenter(), Tables\Columns\ToggleColumn::make('isVisible') ->label('Visibility') ->alignment(Alignment::Center), Tables\Columns\ToggleColumn::make('isAvailable') ->label('Is Available') ->alignment(Alignment::Center), Tables\Columns\ToggleColumn::make('isBogo') ->label('Enable BOGO') ->alignment(Alignment::Center), ]) ->filters([ // ]) ->headerActions([ Tables\Actions\CreateAction::make() ->label('Create New Ticket') ->modalHeading('Create New Ticket'), ]) ->actions([ Tables\Actions\ActionGroup::make([ Tables\Actions\ViewAction::make(), Tables\Actions\EditAction::make(), Tables\Actions\DeleteAction::make(), ]), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DissociateBulkAction::make(), Tables\Actions\DeleteBulkAction::make(), ]), ]); } } ÿþ<?php namespace App\Filament\Resources\EventResource\RelationManagers; use App\Models\Ticket; use Filament\Forms; use Filament\Forms\Components\Section; use Filament\Forms\Form; use Filament\Resources\RelationManagers\RelationManager; use Filament\Tables; use Filament\Tables\Table; class TicketsRelationManager extends RelationManager { protected static string $relationship = 'tickets'; protected static string $model = Ticket::class; public function form(Form $form): Form { return $form ->schema([ Section::make('Ticket File') ->schema([ Forms\Components\FileUpload::make('cover') ->label('Upload Ticket Image') ->image() ->imageEditor() ->columnSpanFull() ->helperText(function (Forms\Get $get) { $path = $get('cover'); if (blank($path)) { return 'Rekomendasi dimensi: 1280%ù720 px (16:9)'; } $file = is_array($path) ? ($path[0] ?? null) : $path; if (! is_string($file)) { return 'Rekomendasi dimensi: 1280%ù720 px (16:9)'; } $full = storage_path('app/public/'.ltrim($file, '/')); if (is_file($full)) { $size = @getimagesize($full); if ($size && isset($size[0], $size[1])) { return 'Dimensi saat ini: '.$size[0].'%ù'.$size[1].' px'; } } return 'Rekomendasi dimensi: 1280%ù720 px (16:9)'; }), Forms\Components\FileUpload::make('layout') ->label('Upload Ticket Downloadable Layout') ->image() ->imageEditor() ->columnSpanFull() ->helperText(function (Forms\Get $get) { $path = $get('layout'); if (blank($path)) { return 'Rekomendasi dimensi: 2480%ù3508 px (A4 portrait, 300 DPI)'; } $file = is_array($path) ? ($path[0] ?? null) : $path; if (! is_string($file)) { return 'Rekomendasi dimensi: 2480%ù3508 px (A4 portrait, 300 DPI)'; } $full = storage_path('app/public/'.ltrim($file, '/')); if (is_file($full)) { $size = @getimagesize($full); if ($size && isset($size[0], $size[1])) { return 'Dimensi saat ini: '.$size[0].'%ù'.$size[1].' px'; } } return 'Rekomendasi dimensi: 2480%ù3508 px (A4 portrait, 300 DPI)'; }), ]), Section::make('Ticket Information') ->schema([ Forms\Components\TextInput::make('name') ->label('Ticket Type') ->required() ->maxLength(255), Forms\Components\TextInput::make('price') ->required() ->numeric() ->prefix('IDR'), Forms\Components\DatePicker::make('startValidDate') ->required() ->native(false), Forms\Components\DatePicker::make('endValidDate') ->required() ->native(false), ]), ]); } public function table(Table $table): Table { return $table ->recordTitleAttribute('name') ->columns([ Tables\Columns\TextColumn::make('name') ->label('Ticket Type') ->sortable(), Tables\Columns\TextColumn::make('price') ->label('Price') ->sortable() ->money('IDR'), Tables\Columns\TextColumn::make('startValidDate') ->label('Valid From') ->date(), Tables\Columns\TextColumn::make('endValidDate') ->label('Valid Until') ->date(), ]) ->filters([ // ]) ->headerActions([ Tables\Actions\CreateAction::make() ->label('Create Ticket') ->modalHeading('Create Ticket'), ]) ->actions([ Tables\Actions\ActionGroup::make([ Tables\Actions\EditAction::make(), Tables\Actions\DeleteAction::make(), ]), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), ]), ]); } } ÿþ<?php namespace App\Filament\Resources; use App\Filament\Resources\PaymentMethodResource\Pages; use App\Models\PaymentMethod; use Filament\Forms; use Filament\Forms\Form; use Filament\Resources\Resource; use Filament\Tables; use Filament\Tables\Table; class PaymentMethodResource extends Resource { protected static ?string $model = PaymentMethod::class; protected static ?string $navigationIcon = 'ri-currency-line'; protected static ?string $navigationGroup = 'App Management'; protected static ?int $navigationSort = 1; protected static function normalizeCoverState(mixed $state): array { if (is_null($state)) { return []; } if (is_string($state)) { return [$state]; } if (! is_array($state)) { return []; } $files = []; foreach ($state as $value) { if (is_string($value)) { $files[] = $value; continue; } if (is_array($value)) { $candidate = $value['path'] ?? $value['file'] ?? $value['filename'] ?? null; if (is_string($candidate)) { $files[] = $candidate; } } } return array_values(array_unique(array_filter($files, fn ($v) => is_string($v) && $v !== ''))); } public static function form(Form $form): Form { return $form ->schema([ Forms\Components\TextInput::make('name') ->required() ->maxLength(255), Forms\Components\TextInput::make('code') ->required() ->unique(ignoreRecord: true) ->maxLength(255), Forms\Components\TextInput::make('slug') ->required() ->unique(ignoreRecord: true) ->maxLength(255), Forms\Components\Select::make('group') ->options([ 'virtual_account' => 'Virtual Account', 'qris' => 'QRIS', 'e-wallet' => 'E-Wallet', 'store' => 'Convenience Store', ]) ->required(), Forms\Components\FileUpload::make('cover') ->image() ->disk(config('filament.default_filesystem_disk')) ->directory('payment-methods') ->multiple() ->maxFiles(1) ->helperText(function (Forms\Get $get) { $state = static::normalizeCoverState($get('cover')); $file = $state[0] ?? null; if (! is_string($file) || $file === '') { return 'Rekomendasi: 512%ù512 px (rasio 1:1), PNG transparan.'; } $full = storage_path('app/public/'.ltrim($file, '/')); if (is_file($full)) { $size = @getimagesize($full); if ($size && isset($size[0], $size[1])) { return 'Dimensi saat ini: '.$size[0].'%ù'.$size[1].' px'; } } return 'Rekomendasi: 512%ù512 px (rasio 1:1), PNG transparan.'; }) ->afterStateHydrated(fn (Forms\Components\FileUpload $component, mixed $state) => $component->state(static::normalizeCoverState($state))) ->dehydrateStateUsing(fn (mixed $state) => static::normalizeCoverState($state)) ->columnSpanFull(), Forms\Components\Toggle::make('isAvailable') ->label('Available') ->default(true), ]); } public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\ImageColumn::make('cover') ->disk(config('filament.default_filesystem_disk')) ->getStateUsing(function (PaymentMethod $record): ?string { return static::normalizeCoverState($record->cover)[0] ?? null; }), Tables\Columns\TextColumn::make('name') ->searchable(), Tables\Columns\TextColumn::make('code') ->searchable(), Tables\Columns\TextColumn::make('group') ->badge() ->searchable(), Tables\Columns\ToggleColumn::make('isAvailable') ->label('Available'), Tables\Columns\TextColumn::make('created_at') ->dateTime() ->sortable() ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('updated_at') ->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\ListPaymentMethods::route('/'), 'create' => Pages\CreatePaymentMethod::route('/create'), 'view' => Pages\ViewPaymentMethod::route('/{record}'), 'edit' => Pages\EditPaymentMethod::route('/{record}/edit'), ]; } } ÿþ<?php namespace App\Filament\Resources; use App\Filament\Resources\PromoResource\Pages; use App\Models\Event; use App\Models\PaymentMethod; use App\Models\Promo; use App\Models\Ticket; use Filament\Forms; use Filament\Forms\Form; use Filament\Infolists; use Filament\Infolists\Infolist; use Filament\Notifications\Notification; use Filament\Pages\Page; use Filament\Pages\SubNavigationPosition; use Filament\Resources\Resource; use Filament\Support\Enums\Alignment; use Filament\Tables; use Filament\Tables\Table; use Illuminate\Support\Str; class PromoResource extends Resource { protected static ?string $model = Promo::class; protected static ?string $navigationIcon = 'ri-discount-percent-line'; protected static ?string $navigationGroup = 'App Management'; protected static ?int $navigationSort = 1; protected static SubNavigationPosition $subNavigationPosition = SubNavigationPosition::Start; public static function infolist(Infolist $infolist): Infolist { return $infolist ->schema([ Infolists\Components\Section::make('Promo Information') ->schema([ Infolists\Components\TextEntry::make('code') ->label('Promo Code') ->copyable() ->columnSpanFull(), Infolists\Components\TextEntry::make('name') ->label('Name') ->columnSpanFull(), Infolists\Components\TextEntry::make('quantity') ->label('Stock') ->columnSpanFull(), Infolists\Components\TextEntry::make('discount') ->label('Discount') ->numeric() ->suffix('%'), Infolists\Components\TextEntry::make('max_discount') ->label('Maximum Discount') ->money('IDR'), Infolists\Components\TextEntry::make('payment_method') ->label('Payment Method'), Infolists\Components\IconEntry::make('isAvailable') ->label('Is Active') ->boolean(), ])->columns(2), ]); } public static function form(Form $form): Form { return $form ->schema([ Forms\Components\Section::make('Promo Banner') ->schema([ Forms\Components\FileUpload::make('cover') ->label('Promo Banner') ->required() ->image() ->imageEditor() ->columnSpanFull() ->helperText(function (Forms\Get $get) { $path = $get('cover'); if (blank($path)) { return 'Rekomendasi dimensi: 1920%ù1080 px (16:9)'; } $file = is_array($path) ? ($path[0] ?? null) : $path; if (! is_string($file)) { return 'Rekomendasi dimensi: 1920%ù1080 px (16:9)'; } $full = storage_path('app/public/'.ltrim($file, '/')); if (is_file($full)) { $size = @getimagesize($full); if ($size && isset($size[0], $size[1])) { return 'Dimensi saat ini: '.$size[0].'%ù'.$size[1].' px'; } } return 'Rekomendasi dimensi: 1920%ù1080 px (16:9)'; }), ]), Forms\Components\Section::make('Promo Information') ->schema([ Forms\Components\Select::make('event_id') ->label('Select Event') ->options(Event::all()->pluck('name', 'id')) ->native(false) ->preload() ->live() ->default(fn (?Promo $record) => $record?->ticket?->event_id) ->dehydrated(false) ->afterStateUpdated(fn (callable $set) => $set('ticket_id', null)) ->columnSpanFull(), Forms\Components\Select::make('ticket_id') ->label('Select Ticket') ->native(false) ->live() ->preload() ->required(fn (string $operation): bool => $operation === 'create') ->disabled(fn (Forms\Get $get): bool => ! filled($get('event_id'))) ->placeholder(fn (Forms\Get $get): string => empty($get('event_id')) ? 'First select events' : 'Select an option') ->options(function (Forms\Get $get) { return Ticket::where('event_id', $get('event_id'))->pluck('name', 'id'); }) ->columnSpanFull(), Forms\Components\TextInput::make('code') ->label('Promo Code') ->required() ->columnSpanFull(), Forms\Components\TextInput::make('name') ->label('Promo Name') ->required() ->columnSpanFull(), Forms\Components\TextInput::make('quantity') ->label('Promo Stock') ->required() ->columnSpanFull(), Forms\Components\TextInput::make('discount') ->label('Promo Discount') ->numeric() ->step(1) ->suffix('%') ->required(), Forms\Components\TextInput::make('max_discount') ->label('Promo Max Discount') ->numeric() ->prefix('IDR') ->required(), Forms\Components\Select::make('payment_method') ->label('Payment Method') ->required() ->columnSpanFull() ->options(PaymentMethod::all()->pluck('name', 'code')) ->native(false), Forms\Components\Hidden::make('slug') ->dehydrateStateUsing(fn (Forms\Get $get) => Str::slug((string) $get('code'))), ])->columns(2), ]); } public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\TextColumn::make('code') ->alignment(Alignment::Center), Tables\Columns\TextColumn::make('ticket.event.name') ->label('Event Name') ->sortable() ->searchable(), Tables\Columns\TextColumn::make('ticket.name') ->label('Ticket Type') ->sortable() ->searchable(), Tables\Columns\TextColumn::make('name') ->label('Promo Name') ->sortable() ->searchable(), Tables\Columns\TextColumn::make('quantity') ->label('Quantity Left') ->alignment(Alignment::Center), Tables\Columns\TextColumn::make('discount') ->suffix('%') ->alignment(Alignment::Center), Tables\Columns\TextColumn::make('max_discount') ->money('IDR') ->sortable() ->alignment(Alignment::Center), Tables\Columns\TextColumn::make('payment_method') ->sortable() ->alignment(Alignment::Center), Tables\Columns\ToggleColumn::make('isAvailable') ->label('Is Available') ->alignment(Alignment::Center), ]) ->filters([ // ]) ->actions([ Tables\Actions\ActionGroup::make([ Tables\Actions\ViewAction::make(), Tables\Actions\EditAction::make() ->successNotification( Notification::make() ->success() ->title('Promo updated') ->body('The promo has been saved successfully.'), ), Tables\Actions\DeleteAction::make(), ]), ]) ->headerActions([ Tables\Actions\CreateAction::make() ->label('Create Promo'), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), ]), ]); } public static function getRelations(): array { return [ // ]; } public static function getRecordSubNavigation(Page $page): array { return $page->generateNavigationItems([ Pages\ViewPromo::class, Pages\EditPromo::class, ]); } public static function getPages(): array { return [ 'index' => Pages\ListPromos::route('/'), // 'create' => Pages\CreatePromo::route('/create'), 'view' => Pages\ViewPromo::route('/{record}'), 'edit' => Pages\EditPromo::route('/{record}/edit'), ]; } } ÿþ<?php namespace App\Filament\Resources; use App\Filament\Resources\TicketResource\Pages; use App\Models\Ticket; use Filament\Forms; use Filament\Forms\Components\Section; use Filament\Forms\Form; use Filament\Resources\Resource; use Filament\Support\Enums\Alignment; use Filament\Tables; use Filament\Tables\Table; class TicketResource extends Resource { protected static ?string $model = Ticket::class; protected static ?string $navigationIcon = 'ri-coupon-line'; protected static ?string $navigationGroup = 'Event Management'; protected static ?int $navigationSort = 2; public static function form(Form $form): Form { return $form ->schema([ Section::make('Ticket Image') ->schema([ Forms\Components\FileUpload::make('cover') ->label('Upload Ticket Image') ->image() ->imageEditor() ->columnSpanFull() ->helperText(function (Forms\Get $get) { $path = $get('cover'); if (blank($path)) { return 'Rekomendasi dimensi: 1280%ù720 px (16:9)'; } $file = is_array($path) ? ($path[0] ?? null) : $path; if (! is_string($file)) { return 'Rekomendasi dimensi: 1280%ù720 px (16:9)'; } $full = storage_path('app/public/'.ltrim($file, '/')); if (is_file($full)) { $size = @getimagesize($full); if ($size && isset($size[0], $size[1])) { return 'Dimensi saat ini: '.$size[0].'%ù'.$size[1].' px'; } } return 'Rekomendasi dimensi: 1280%ù720 px (16:9)'; }), Forms\Components\FileUpload::make('layout') ->label('Upload Ticket Downloadable Layout') ->image() ->imageEditor() ->columnSpanFull() ->helperText(function (Forms\Get $get) { $path = $get('layout'); if (blank($path)) { return 'Rekomendasi dimensi: 2480%ù3508 px (A4 portrait, 300 DPI)'; } $file = is_array($path) ? ($path[0] ?? null) : $path; if (! is_string($file)) { return 'Rekomendasi dimensi: 2480%ù3508 px (A4 portrait, 300 DPI)'; } $full = storage_path('app/public/'.ltrim($file, '/')); if (is_file($full)) { $size = @getimagesize($full); if ($size && isset($size[0], $size[1])) { return 'Dimensi saat ini: '.$size[0].'%ù'.$size[1].' px'; } } return 'Rekomendasi dimensi: 2480%ù3508 px (A4 portrait, 300 DPI)'; }), ]), Section::make('Ticket Information') ->schema([ Forms\Components\TextInput::make('name') ->label('Ticket Type') ->required() ->maxLength(255), Forms\Components\TextInput::make('price') ->required() ->numeric() ->prefix('IDR'), Forms\Components\DatePicker::make('startValidDate') ->required() ->native(false), Forms\Components\DatePicker::make('endValidDate') ->required() ->native(false), ]), ]); } public static function table(Table $table): Table { return $table ->reorderable('sort') ->columns([ Tables\Columns\TextColumn::make('event.name') ->label('Event Name') ->sortable() ->searchable(), Tables\Columns\TextColumn::make('name') ->label('Ticket Type') ->searchable(), Tables\Columns\TextColumn::make('price') ->label('Price') ->sortable() ->money('IDR'), Tables\Columns\TextColumn::make('startValidDate') ->label('Valid From') ->date(), Tables\Columns\TextColumn::make('endValidDate') ->label('Valid Until') ->date(), Tables\Columns\TextColumn::make('generated_tickets_count') ->label('Total Sold') ->counts('generatedTickets') ->searchable() ->alignCenter(), Tables\Columns\ToggleColumn::make('isVisible') ->label('Visibility') ->alignment(Alignment::Center), Tables\Columns\ToggleColumn::make('isAvailable') ->label('Is Available') ->alignment(Alignment::Center), Tables\Columns\ToggleColumn::make('isBogo') ->label('Enable BOGO') ->alignment(Alignment::Center), Tables\Columns\TextColumn::make('created_at') ->dateTime() ->sortable() ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('updated_at') ->dateTime() ->sortable() ->toggleable(isToggledHiddenByDefault: true), ]) ->defaultSort('created_at', 'desc') ->filters([ // ]) ->actions([ Tables\Actions\ActionGroup::make([ Tables\Actions\EditAction::make() ->label('Edit Ticket') ->modalHeading(fn (Ticket $ticket) => 'Editing '.$ticket->event->name.' '.$ticket->name), 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\ListTickets::route('/'), // 'create' => Pages\CreateTicket::route('/create'), // 'edit' => Pages\EditTicket::route('/{record}/edit'), ]; } } Not Found
404
Not Found