components([ SC\KeyValue::make('name')->label('Name (de/en)')->keyLabel('locale')->valueLabel('value')->default(['de' => '', 'en' => ''])->required(), SC\TextInput::make('icon')->label('Icon/Emoji')->maxLength(50), SC\TextInput::make('color')->maxLength(7)->helperText('#RRGGBB'), SC\KeyValue::make('description')->label('Description (de/en)')->keyLabel('locale')->valueLabel('value'), SC\TextInput::make('sort_order')->numeric()->default(0), SC\Toggle::make('is_active')->default(true), SC\Select::make('eventTypes') ->label('Event Types') ->multiple() ->searchable() ->preload() ->relationship('eventTypes', 'name'), ])->columns(2); } public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\TextColumn::make('id')->sortable(), Tables\Columns\TextColumn::make('name')->searchable(), Tables\Columns\TextColumn::make('icon'), Tables\Columns\TextColumn::make('color'), Tables\Columns\IconColumn::make('is_active')->boolean(), Tables\Columns\TextColumn::make('sort_order')->sortable(), ]) ->filters([]) ->actions([ Tables\Actions\EditAction::make(), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), ]), ]); } public static function getPages(): array { return [ 'index' => Pages\ManageEmotions::route('/'), 'import' => Pages\ImportEmotions::route('/import'), ]; } } namespace App\Filament\Resources\EmotionResource\Pages; use App\Filament\Resources\EmotionResource; use Filament\Resources\Pages\ManageRecords; use Filament\Actions; use Filament\Resources\Pages\Page; use Filament\Forms; use Filament\Notifications\Notification; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\DB; class ManageEmotions extends ManageRecords { protected static string $resource = EmotionResource::class; protected function getHeaderActions(): array { return [ Actions\Action::make('import') ->label('Import CSV') ->icon('heroicon-o-arrow-up-tray') ->url(EmotionResource::getUrl('import')), Actions\Action::make('template') ->label('Download CSV Template') ->icon('heroicon-o-document-arrow-down') ->url(url('/super-admin/templates/emotions.csv')), ]; } } class ImportEmotions extends Page { protected static string $resource = EmotionResource::class; protected string $view = 'filament.pages.blank'; protected ?string $heading = 'Import Emotions (CSV)'; public ?string $file = null; protected function getFormSchema(): array { return [ Forms\Components\FileUpload::make('file') ->label('CSV file') ->acceptedFileTypes(['text/csv', 'text/plain']) ->directory('imports') ->required(), ]; } protected function getFormActions(): array { return [ Forms\Components\Actions\Action::make('import') ->label('Import') ->action('doImport') ->color('primary') ]; } public function doImport(): void { $state = $this->form->getState(); $path = $state['file'] ?? null; if (! $path || ! Storage::disk('public')->exists($path)) { Notification::make()->danger()->title('File not found')->send(); return; } $full = Storage::disk('public')->path($path); [$ok, $fail] = $this->importEmotionsCsv($full); Notification::make()->success()->title("Imported {$ok} rows")->body($fail ? "{$fail} failed" : null)->send(); } private function importEmotionsCsv(string $file): array { $h = fopen($file, 'r'); if (! $h) return [0,0]; $ok = 0; $fail = 0; // Expected headers: name_de,name_en,icon,color,description_de,description_en,sort_order,is_active,event_types $headers = fgetcsv($h, 0, ','); if (! $headers) return [0,0]; $map = array_flip($headers); while (($row = fgetcsv($h, 0, ',')) !== false) { try { $nameDe = trim($row[$map['name_de']] ?? ''); $nameEn = trim($row[$map['name_en']] ?? ''); $name = $nameDe ?: $nameEn; if ($name === '') { $fail++; continue; } $data = [ 'name' => ['de' => $nameDe, 'en' => $nameEn], 'icon' => $row[$map['icon']] ?? null, 'color' => $row[$map['color']] ?? null, 'description' => [ 'de' => $row[$map['description_de']] ?? null, 'en' => $row[$map['description_en']] ?? null, ], 'sort_order' => (int)($row[$map['sort_order']] ?? 0), 'is_active' => (int)($row[$map['is_active']] ?? 1) ? 1 : 0, ]; $id = DB::table('emotions')->insertGetId(array_merge($data, [ 'created_at' => now(), 'updated_at' => now(), ])); // Attach event types if provided (by slug list separated by '|') $et = $row[$map['event_types']] ?? ''; if ($et) { $slugs = array_filter(array_map('trim', explode('|', $et))); if ($slugs) { $ids = DB::table('event_types')->whereIn('slug', $slugs)->pluck('id')->all(); foreach ($ids as $eid) { DB::table('emotion_event_type')->insertOrIgnore([ 'emotion_id' => $id, 'event_type_id' => $eid, ]); } } } $ok++; } catch (\Throwable $e) { $fail++; } } fclose($h); return [$ok, $fail]; } }