diff --git a/src/TodoistVisualizer.js b/src/TodoistVisualizer.js index 914537b..a06581e 100644 --- a/src/TodoistVisualizer.js +++ b/src/TodoistVisualizer.js @@ -3,6 +3,8 @@ import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'; import { Checkbox } from '@/components/ui/checkbox'; import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; +import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; +import { AlertCircle, Loader2 } from 'lucide-react'; const TodoistVisualizer = () => { const [apiKey, setApiKey] = useState(''); @@ -11,30 +13,56 @@ const TodoistVisualizer = () => { const [selectedItems, setSelectedItems] = useState([]); const [loading, setLoading] = useState(false); const [images, setImages] = useState({}); + const [error, setError] = useState(null); + const [imageGenerating, setImageGenerating] = useState(false); const fetchTodoistData = async () => { setLoading(true); + setError(null); try { + // Validate API key + if (!apiKey.trim()) { + throw new Error('Please enter your Todoist API key'); + } + + // Fetch favorites const favResponse = await fetch('https://api.todoist.com/rest/v2/favorites', { headers: { 'Authorization': `Bearer ${apiKey}` } }); + + if (!favResponse.ok) { + if (favResponse.status === 401) { + throw new Error('Invalid API key. Please check and try again.'); + } + throw new Error('Failed to fetch favorites. Please try again.'); + } + const favData = await favResponse.json(); + // Fetch filters const filterResponse = await fetch('https://api.todoist.com/rest/v2/filters', { headers: { 'Authorization': `Bearer ${apiKey}` } }); + + if (!filterResponse.ok) { + throw new Error('Failed to fetch filters. Please try again.'); + } + const filterData = await filterResponse.json(); setFavorites(favData); setFilters(filterData); } catch (error) { - console.error('Error fetching Todoist data:', error); + setError(error.message); + setFavorites([]); + setFilters([]); + } finally { + setLoading(false); } - setLoading(false); }; const handleItemToggle = (id) => { @@ -47,11 +75,26 @@ const TodoistVisualizer = () => { }; const generateImages = async () => { - const newImages = {}; - selectedItems.forEach(id => { - newImages[id] = '/api/placeholder/300/200'; - }); - setImages(newImages); + setImageGenerating(true); + setError(null); + try { + if (selectedItems.length === 0) { + throw new Error('Please select at least one item to visualize'); + } + + // Placeholder for image generation + const newImages = {}; + for (const id of selectedItems) { + // Simulate API call with delay + await new Promise(resolve => setTimeout(resolve, 1000)); + newImages[id] = '/api/placeholder/300/200'; + } + setImages(newImages); + } catch (error) { + setError(error.message); + } finally { + setImageGenerating(false); + } }; return ( @@ -62,6 +105,14 @@ const TodoistVisualizer = () => {
+ {error && ( + + + Error + {error} + + )} +
{ value={apiKey} onChange={(e) => setApiKey(e.target.value)} className="flex-1" + disabled={loading} />

Favorites

+ {favorites.length === 0 && !loading && ( +

No favorites found. Connect your Todoist account to see your favorites.

+ )}
{favorites.map(favorite => (
@@ -101,6 +160,9 @@ const TodoistVisualizer = () => {

Filters

+ {filters.length === 0 && !loading && ( +

No filters found. Create filters in Todoist to see them here.

+ )}
{filters.map(filter => (
@@ -124,10 +186,13 @@ const TodoistVisualizer = () => {
diff --git a/src/components/ErrorAlert.js b/src/components/ErrorAlert.js new file mode 100644 index 0000000..7c25de7 --- /dev/null +++ b/src/components/ErrorAlert.js @@ -0,0 +1,13 @@ +import React from 'react'; +import { Alert, AlertTitle, AlertDescription } from '@/components/ui/alert'; + +const ErrorAlert = ({ message, onClose }) => { + return ( + + Error + {message} + + ); +}; + +export default ErrorAlert; \ No newline at end of file