tenant->id; $query = Emotion::query() ->whereNull('tenant_id') ->orWhere('tenant_id', $tenantId) ->with('eventTypes'); if ($request->boolean('only_tenant')) { $query->where('tenant_id', $tenantId); } if ($request->boolean('only_global')) { $query->whereNull('tenant_id'); } $query->orderByRaw('tenant_id is null desc')->orderBy('sort_order')->orderBy('id'); $emotions = $query->paginate($request->integer('per_page', 25)); return EmotionResource::collection($emotions); } public function store(EmotionStoreRequest $request): JsonResponse { $data = $request->validated(); $payload = [ 'tenant_id' => $request->tenant->id, 'name' => $this->localizeValue($data['name']), 'description' => $this->localizeValue($data['description'] ?? null, allowNull: true), 'icon' => $data['icon'] ?? 'lucide-smile', 'color' => $this->normalizeColor($data['color'] ?? '#6366f1'), 'sort_order' => $data['sort_order'] ?? 0, 'is_active' => $data['is_active'] ?? true, ]; $emotion = null; DB::transaction(function () use (&$emotion, $payload, $data) { $emotion = Emotion::create($payload); if (! empty($data['event_type_ids'])) { $emotion->eventTypes()->sync($data['event_type_ids']); } }); return response()->json([ 'message' => __('Emotion erfolgreich erstellt.'), 'data' => new EmotionResource($emotion->fresh('eventTypes')), ], 201); } public function update(EmotionUpdateRequest $request, Emotion $emotion): JsonResponse { if ($emotion->tenant_id && $emotion->tenant_id !== $request->tenant->id) { abort(403, 'Emotion gehört nicht zu diesem Tenant.'); } if (is_null($emotion->tenant_id) && $request->hasAny(['name', 'description', 'icon', 'color', 'sort_order'])) { abort(403, 'Globale Emotions können nicht bearbeitet werden.'); } $data = $request->validated(); DB::transaction(function () use ($emotion, $data) { $update = []; if (array_key_exists('name', $data)) { $update['name'] = $this->localizeValue($data['name'], allowNull: false, fallback: $emotion->name); } if (array_key_exists('description', $data)) { $update['description'] = $this->localizeValue($data['description'], allowNull: true, fallback: $emotion->description); } if (array_key_exists('icon', $data)) { $update['icon'] = $data['icon'] ?? $emotion->icon; } if (array_key_exists('color', $data)) { $update['color'] = $this->normalizeColor($data['color'] ?? $emotion->color); } if (array_key_exists('sort_order', $data)) { $update['sort_order'] = $data['sort_order'] ?? 0; } if (array_key_exists('is_active', $data)) { $update['is_active'] = $data['is_active']; } if (! empty($update)) { $emotion->update($update); } if (array_key_exists('event_type_ids', $data)) { $emotion->eventTypes()->sync($data['event_type_ids'] ?? []); } }); return response()->json([ 'message' => __('Emotion aktualisiert.'), 'data' => new EmotionResource($emotion->fresh('eventTypes')), ]); } protected function localizeValue(mixed $value, bool $allowNull = false, ?array $fallback = null): ?array { if ($allowNull && ($value === null || $value === '')) { return null; } if (is_array($value)) { $filtered = array_filter($value, static fn ($text) => is_string($text) && $text !== ''); if (! empty($filtered)) { return $filtered; } return $allowNull ? null : ($fallback ?? []); } if (is_string($value) && $value !== '') { $locale = app()->getLocale() ?: 'de'; return [$locale => $value]; } return $allowNull ? null : $fallback; } protected function normalizeColor(string $color): string { $normalized = ltrim($color, '#'); if (strlen($normalized) === 6) { return '#' . strtolower($normalized); } return '#6366f1'; } }