diff --git a/TODO.md b/TODO.md index 4637707..df8b4e3 100644 --- a/TODO.md +++ b/TODO.md @@ -19,7 +19,7 @@ - [x] Initialize React + Vite project - [x] Configure Tailwind CSS - [x] Set up React Router -- [ ] Create recipe list page +- [x] Create recipe list page - [ ] Create recipe detail/edit page - [ ] Implement cook mode UI @@ -46,6 +46,16 @@ ## ✅ Completed Tasks ### 2026-03-24 +- **Recipe list page implementation** + - Created API client service (src/services/api.ts) with all CRUD operations + - Created useRecipes hook for data fetching with search and pagination + - Created RecipeCard component for displaying individual recipes + - Implemented RecipeListPage with search bar, empty state, loading state, error handling + - Added grid layout with responsive design (1-3 columns) + - Implemented "Load More" button for pagination + - Added recipe count display and meta information (servings, time, last cooked) + - Verified TypeScript compilation and Vite build succeed + - **React Router setup** - Updated main.tsx to wrap App in BrowserRouter - Configured routes in App.tsx with navigation header diff --git a/frontend/src/components/RecipeCard.tsx b/frontend/src/components/RecipeCard.tsx new file mode 100644 index 0000000..f35cb2e --- /dev/null +++ b/frontend/src/components/RecipeCard.tsx @@ -0,0 +1,87 @@ +/** + * RecipeCard - Displays a single recipe in the list view + */ + +import { Link } from 'react-router-dom'; +import type { Recipe } from '../types/recipe'; + +interface RecipeCardProps { + recipe: Recipe; +} + +/** + * Format time in minutes to readable string + */ +function formatTime(minutes?: number): string { + if (!minutes) return ''; + if (minutes < 60) return `${minutes}m`; + const hours = Math.floor(minutes / 60); + const mins = minutes % 60; + return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`; +} + +/** + * Format date timestamp to readable string + */ +function formatDate(timestamp?: number): string { + if (!timestamp) return ''; + const date = new Date(timestamp * 1000); + return date.toLocaleDateString(); +} + +export function RecipeCard({ recipe }: RecipeCardProps) { + const totalTime = (recipe.prep_time_minutes || 0) + (recipe.cook_time_minutes || 0); + + return ( + +
+ {recipe.description} +
+ )} + + {/* Meta information */} +- Browse and search your recipe collection -
-- Recipe list will be implemented here (next task) -
++ Browse and search your recipe collection +
++ Searching for: "{searchQuery}" +
+ )}+ Error: {error} +
+Loading recipes...
++ {searchQuery + ? 'Try a different search term' + : 'Get started by adding your first recipe'} +
+ {!searchQuery && ( + + Add Your First Recipe + + )} +