149 lines
5.0 KiB
TypeScript
149 lines
5.0 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
import { Button } from '@/components/ui/button';
|
|
import { ChevronRight } from 'lucide-react';
|
|
|
|
interface Emotion {
|
|
id: number;
|
|
slug: string;
|
|
name: string;
|
|
emoji: string;
|
|
description?: string;
|
|
}
|
|
|
|
interface EmotionPickerProps {
|
|
onSelect?: (emotion: Emotion) => void;
|
|
}
|
|
|
|
export default function EmotionPicker({ onSelect }: EmotionPickerProps) {
|
|
const { slug } = useParams<{ slug: string }>();
|
|
const navigate = useNavigate();
|
|
const [emotions, setEmotions] = useState<Emotion[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
// Fallback emotions (when API not available yet)
|
|
const fallbackEmotions: Emotion[] = [
|
|
{ id: 1, slug: 'happy', name: 'Glücklich', emoji: '😊' },
|
|
{ id: 2, slug: 'love', name: 'Verliebt', emoji: '❤️' },
|
|
{ id: 3, slug: 'excited', name: 'Aufgeregt', emoji: '🎉' },
|
|
{ id: 4, slug: 'relaxed', name: 'Entspannt', emoji: '😌' },
|
|
{ id: 5, slug: 'sad', name: 'Traurig', emoji: '😢' },
|
|
{ id: 6, slug: 'surprised', name: 'Überrascht', emoji: '😲' },
|
|
];
|
|
|
|
useEffect(() => {
|
|
if (!slug) return;
|
|
|
|
async function fetchEmotions() {
|
|
try {
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
// Try API first
|
|
const response = await fetch(`/api/v1/events/${slug}/emotions`);
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
setEmotions(Array.isArray(data) ? data : fallbackEmotions);
|
|
} else {
|
|
// Fallback to predefined emotions
|
|
console.warn('Emotions API not available, using fallback');
|
|
setEmotions(fallbackEmotions);
|
|
}
|
|
} catch (err) {
|
|
console.error('Failed to fetch emotions:', err);
|
|
setError('Emotions konnten nicht geladen werden');
|
|
setEmotions(fallbackEmotions);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
|
|
fetchEmotions();
|
|
}, [slug]);
|
|
|
|
const handleEmotionSelect = (emotion: Emotion) => {
|
|
if (onSelect) {
|
|
onSelect(emotion);
|
|
} else {
|
|
// Default: Navigate to tasks with emotion filter
|
|
navigate(`/e/${slug}/tasks?emotion=${emotion.slug}`);
|
|
}
|
|
};
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="mb-6 p-4 text-center">
|
|
<div className="text-sm text-muted-foreground">Lade Emotionen...</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (error) {
|
|
return (
|
|
<div className="mb-6 p-4 bg-red-50 border border-red-200 rounded-lg">
|
|
<div className="text-sm text-red-700">{error}</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="mb-6">
|
|
<h3 className="text-lg font-semibold mb-4 flex items-center gap-2">
|
|
Wie fühlst du dich?
|
|
<span className="text-xs text-muted-foreground">(optional)</span>
|
|
</h3>
|
|
|
|
<div className="grid grid-cols-2 md:grid-cols-3 gap-3">
|
|
{emotions.map((emotion) => {
|
|
// Localize name and description if they are JSON
|
|
const localize = (value: string | object, defaultValue: string = ''): string => {
|
|
if (typeof value === 'string' && value.startsWith('{')) {
|
|
try {
|
|
const data = JSON.parse(value as string);
|
|
return data.de || data.en || defaultValue || '';
|
|
} catch {
|
|
return value as string;
|
|
}
|
|
}
|
|
return value as string;
|
|
};
|
|
|
|
const localizedName = localize(emotion.name, emotion.name);
|
|
const localizedDescription = localize(emotion.description || '', '');
|
|
|
|
return (
|
|
<Button
|
|
key={emotion.id}
|
|
variant="outline"
|
|
className="w-full justify-start h-16 p-3 bg-pink-50 dark:bg-gray-800/50 hover:bg-pink-100 dark:hover:bg-gray-700/50 border-pink-200 dark:border-gray-600 rounded-xl text-left shadow-sm dark:text-white"
|
|
onClick={() => handleEmotionSelect(emotion)}
|
|
>
|
|
<div className="flex items-center gap-3">
|
|
<span className="text-2xl">{emotion.emoji}</span>
|
|
<div className="flex-1 min-w-0">
|
|
<div className="font-medium text-sm truncate">{localizedName}</div>
|
|
{localizedDescription && (
|
|
<div className="text-xs text-muted-foreground truncate">{localizedDescription}</div>
|
|
)}
|
|
</div>
|
|
<ChevronRight className="h-4 w-4 text-muted-foreground ml-auto" />
|
|
</div>
|
|
</Button>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
{/* Skip option */}
|
|
<div className="mt-4">
|
|
<Button
|
|
variant="ghost"
|
|
className="w-full text-sm text-gray-600 dark:text-gray-300 hover:text-pink-600 hover:bg-pink-50 dark:hover:bg-gray-800 border-t border-gray-200 dark:border-gray-700 pt-3 mt-3"
|
|
onClick={() => navigate(`/e/${slug}/tasks`)}
|
|
>
|
|
Überspringen und Aufgabe wählen
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |