- DB: users.username (unique), users.preferred_locale (default from app.locale) - Backend: validation, model fillable; share supportedLocales; SetLocaleFromUser - Frontend: profile page fields + types - Filament: SuperAdmin profile page with username/language feat(admin-nav): move Tasks to Bibliothek and add menu labels fix(tasks-table): show localized title/emotion/event type; add translated headers feat(l10n): add missing table headers for emotions and event types; normalize en/de files refactor: tidy translations for tasks/emotions/event types
115 lines
3.8 KiB
PHP
115 lines
3.8 KiB
PHP
<?php
|
|
|
|
namespace App\Filament\Resources\EmotionResource\Pages;
|
|
|
|
use App\Filament\Resources\EmotionResource;
|
|
use App\Models\Emotion;
|
|
use Filament\Forms\Components\FileUpload;
|
|
use Filament\Forms\Form;
|
|
use Filament\Notifications\Notification;
|
|
use Filament\Resources\Pages\Page;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
class ImportEmotions extends Page
|
|
{
|
|
protected static string $resource = EmotionResource::class;
|
|
protected string $view = 'filament.resources.emotion-resource.pages.import-emotions';
|
|
protected ?string $heading = null;
|
|
|
|
public ?string $file = null;
|
|
|
|
public function form(Form $form): Form
|
|
{
|
|
return $form->schema([
|
|
FileUpload::make('file')
|
|
->label(__('admin.common.csv_file'))
|
|
->acceptedFileTypes(['text/csv', 'text/plain'])
|
|
->directory('imports')
|
|
->required(),
|
|
]);
|
|
}
|
|
|
|
public function doImport(): void
|
|
{
|
|
$this->validate();
|
|
|
|
$path = $this->form->getState()['file'] ?? null;
|
|
if (!$path || !Storage::disk('public')->exists($path)) {
|
|
Notification::make()->danger()->title(__('admin.notifications.file_not_found'))->send();
|
|
return;
|
|
}
|
|
|
|
$fullPath = Storage::disk('public')->path($path);
|
|
[$ok, $fail] = $this->importEmotionsCsv($fullPath);
|
|
|
|
Notification::make()
|
|
->success()
|
|
->title(__('admin.notifications.imported_rows', ['count' => $ok]))
|
|
->body($fail ? __('admin.notifications.failed_count', ['count' => $fail]) : null)
|
|
->send();
|
|
}
|
|
|
|
public function getHeading(): string
|
|
{
|
|
return __('admin.emotions.import.heading');
|
|
}
|
|
|
|
private function importEmotionsCsv(string $file): array
|
|
{
|
|
$handle = fopen($file, 'r');
|
|
if (!$handle) {
|
|
return [0, 0];
|
|
}
|
|
|
|
$ok = 0;
|
|
$fail = 0;
|
|
$headers = fgetcsv($handle, 0, ',');
|
|
if (!$headers) {
|
|
return [0, 0];
|
|
}
|
|
|
|
$map = array_flip($headers);
|
|
|
|
while (($row = fgetcsv($handle, 0, ',')) !== false) {
|
|
try {
|
|
DB::transaction(function () use ($row, $map, &$ok) {
|
|
$nameDe = trim($row[$map['name_de']] ?? '');
|
|
$nameEn = trim($row[$map['name_en']] ?? '');
|
|
|
|
if (empty($nameDe) && empty($nameEn)) {
|
|
throw new \Exception('Name is required.');
|
|
}
|
|
|
|
$emotion = Emotion::create([
|
|
'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,
|
|
]);
|
|
|
|
$eventTypes = $row[$map['event_types']] ?? '';
|
|
if ($eventTypes) {
|
|
$slugs = array_filter(array_map('trim', explode('|', $eventTypes)));
|
|
if ($slugs) {
|
|
$eventTypeIds = DB::table('event_types')->whereIn('slug', $slugs)->pluck('id')->all();
|
|
$emotion->eventTypes()->attach($eventTypeIds);
|
|
}
|
|
}
|
|
$ok++;
|
|
});
|
|
} catch (\Throwable $e) {
|
|
$fail++;
|
|
}
|
|
}
|
|
|
|
fclose($handle);
|
|
return [$ok, $fail];
|
|
}
|
|
}
|