columns([ Textcolumn::make('id')->sortable()->searchable()->translateLabel()->formatStateUsing(function ($state, $record, $column) { $prefix = "G"; // Define your desired prefix $paddedValue = str_pad($state, 4, '0', STR_PAD_LEFT); // Adjust padding as needed return $prefix . $paddedValue; // Combine the prefix and the padded value }), SvgColumn::make('icon')->square(false)->translateLabel(), TextColumn::make('name') ->searchable() ->sortable()->translateLabel(), TextColumn::make('tagline')->translateLabel()->searchable()->toggleable(isToggledHiddenByDefault: false)->limit(60), TextColumn::make('state')->translateLabel()->badge()->formatStateUsing(function ($record) { return $record->state->getLabel(); }) ->color(function ($record) { $state = $record->state->value; return match ($state) { 'open' => 'primary', 'new' => 'info', 'finished' => 'success', 'cancelled' => 'danger', 'waiting' => 'warning', 'stale' => 'gray', 'idea' => 'gray', default => 'secondary', }; }), IconColumn::make('hidden')->icon(fn(bool $state): string => match ($state) { true => 'heroicon-s-eye-slash', false => 'heroicon-o-eye' })->translateLabel()->toggleable(isToggledHiddenByDefault: true)->boolean(false), TextColumn::make('customer.name')->translateLabel()->searchable()->toggleable(isToggledHiddenByDefault: false)->sortable()->url(function ($record) { return route('filament.admin.resources.customers.view', ['record' => $record->customer->id]); }), ViewColumn::make('skills')->translateLabel()->view('columns.skills-column',)->toggleable(isToggledHiddenByDefault: true), RatingStarColumn::make('fun')->translateLabel()->toggleable(isToggledHiddenByDefault: true)->sortable(), TextColumn::make('end')->translateLabel()->sortable()->searchable()->toggleable(isToggledHiddenByDefault: true)->date('d.m.y'), TextColumn::make('presentability')->translateLabel()->toggleable(isToggledHiddenByDefault: true), TextColumn::make('hours')->translateLabel()->sortable()->toggleable(isToggledHiddenByDefault: false), TextColumn::make('contact')->translateLabel()->toggleable(isToggledHiddenByDefault: true), RelationshipColumn::make('similar')->translateLabel()->toggleable(isToggledHiddenByDefault: true), RelationshipColumn::make('domains')->translateLabel()->toggleable(isToggledHiddenByDefault: true), ] )->contentGrid([ 'md' => 2, 'xl' => 3, ])->filters([ //show deleted TrashedFilter::make()->translateLabel(), Filter::make('is_open')->query(fn($query) => $query->wherenot('state', 'cancelled'))->label('only active')->translateLabel(), SelectFilter::make('skills')->relationship('skills', 'name')->label('skills')->translateLabel()->searchable()->preload()->multiple(), SelectFilter::make('customer_id')->relationship('customer', 'name')->label('customer')->translateLabel()->searchable()->preload()->multiple(), SelectFilter::make('state')->options([ 'idea' => __('idea'), 'new' => __('new'), 'open' => __('open'), 'finished' => __('finished'), 'cancelled' => __('cancelled'), 'waiting' => __('waiting'), 'stale' => __('stale'), ])->multiple()->label('state')->translateLabel(), SelectFilter::make('hidden')->options([ true => __('hidden'), false => __('visible'), ])->label('visibility')->translateLabel(), Filter::make('public')->label('public')->translateLabel()->query(fn($query) => $query->public()), ]) ->actions([ Action::make("view_public")->label('View')->url(fn(Gig $record) => route('gig', ['id' => $record->id]))->icon('mdi-curtains')->translateLabel()->button(), EditAction::make()->translateLabel(), DeleteAction::make()->translateLabel(), RestoreAction::make()->translateLabel() ]) ->bulkActions([ BulkActionGroup::make([ DeleteBulkAction::make()->translateLabel(), //ForceDeleteBulkAction::make()->translateLabel(), //todo: maybe for admins? RestoreBulkAction::make()->translateLabel(), ExportBulkAction::make()->translateLabel(), ])]) ->defaultSort('id', 'desc') ->groups([Group::make('state') ->label(__('state')), ]); } public static function form(Form $form): Form { return $form ->schema([ Section::make(__('base'))->columns([ 'sm' => 1, 'xl' => 2, '2xl' => 4, ])->translateLabel(true)->schema([ TextInput::make('id')->numeric()->translateLabel()->helperText('Specify an ID only if you need to set it manually; otherwise, leave it blank.') ->nullable() ->dehydrated(fn($state): bool => filled($state)), // Only save if filled, TextInput::make('name') ->required()->translateLabel(), TextInput::make('tagline') ->required()->translateLabel(), Select::make('state') ->options([ 'new' => __('new'), 'idea' => __("idea"), 'open' => __('open'), 'finished' => __('finished'), 'cancelled' => __('cancelled'), 'waiting' => __('waiting'), 'stale' => __('stale') ])->default("idea") ->required()->translateLabel(), Select::make('skills')->multiple()->relationship('skills', 'name')->translateLabel()->searchable()->preload()->preload()->createOptionForm(SkillResource::getSchema()), Select::make('customer_id')->relationship(name: 'customer', titleAttribute: 'name')->required()->translateLabel()->searchable()->preload()->createOptionForm(CustomerResource::getSchema()), TextInput::make('contact')->translateLabel()->nullable(), Checkbox::make('hidden')->translateLabel(), FileUpload::make('heropic')->acceptedFileTypes(["image/*"])->translateLabel(), FileUpload::make('icon')->acceptedFileTypes(["image/*"])->translateLabel(), ]), Section::make(__('details'))->schema([ Select::make('domains')->multiple()->relationship('domains', 'name')->translateLabel()->searchable()->preload()->createOptionForm(DomainResource::getSchema()), ]), Section::make(__('opinion'))->schema([ TextInput::make('opinion') ->nullable()->translateLabel(), Checkbox::make('epic_opinion')->translateLabel()->rules([ function () { return function (string $attribute, $value, Closure $fail) { $totalRows = Gig::public()->count(); $trueCount = Gig::where('epic_opinion', '=', true)->count(); if ($totalRows === 0) { return; } $percentage = ($trueCount / $totalRows) * 100; if ($value === True && $percentage > 15) { $fail(__('No more than 15% of public gigs can have an epic opinion.')); } }; }, ])->helperText(__('epic feedback will be highlighted on the gig overview')), ]), Section::make(__('end'))->schema([MarkdownEditor::make('text')->translateLabel(), DatePicker::make('end')->translateLabel(), TextInput::make('hours')->translateLabel()->numeric()->nullable()->rules(['integer', 'min:0']), TextInput::make('learned') ->translateLabel(), RatingStar::make('fun')->translateLabel(), Placeholder::make('created_at') ->label('Created Date') ->content(fn(?Gig $record): string => $record?->created_at?->diffForHumans() ?? '-')->translateLabel(), Placeholder::make('updated_at') ->label('Last Modified Date') ->content(fn(?Gig $record): string => $record?->updated_at?->diffForHumans() ?? '-')->translateLabel(), ])]); } public static function getPages(): array { return [ 'index' => Pages\ListGigs::route('/'), 'create' => Pages\CreateGig::route('/create'), 'edit' => Pages\EditGig::route('/{record}/edit'), ]; } public static function getGloballySearchableAttributes(): array { $parent_aatributes = parent::getGloballySearchableAttributes(); $atributes = ['name']; return array_merge($parent_aatributes, $atributes); } }